[英]How to Slow Down React State Update Intentionally - Batch Updates
Occasionally I may want to unmount and remount a component with new data inside it.有时我可能想卸载并重新安装一个组件,其中包含新数据。 This could look like:
这可能看起来像:
setAllPosts(undefined);
setAllPosts(newArrayOfPosts);
Because React batches state changes, depending on where the newArrayOfPosts is coming from, the state won't change.因为 React 批处理状态变化,取决于 newArrayOfPosts 来自哪里,状态不会改变。 I've been able to hack a solution with a setTimeout() of 1 second and then filling in setAllPosts(), but this feels so wrong.
我已经能够破解一个 setTimeout() 为 1 秒的解决方案,然后填写 setAllPosts(),但这感觉太不对劲了。
Is there a best practice way to tell React to slow down for a moment?有没有一种最佳实践方法来告诉 React 放慢速度? or maybe to not batch update this particular state change?
或者也许不批量更新这个特定的状态变化?
PS I know there are better ways to do this, but I am working inside a third party environment and am pretty limited to what I have access to. PS 我知道有更好的方法可以做到这一点,但我在第三方环境中工作,并且非常受限于我可以访问的内容。
Once react 18 is available (it's currently a release-candidate) there will be a function that can force updates to not be batched: flushSync
一旦 react 18 可用(它目前是一个候选版本),就会有一个函数可以强制更新不被批处理:
flushSync
import { flushSync } from 'react-dom';
flushSync(() => {
setAllPosts(undefined);
});
flushSync(() => {
setAllPosts(newArrayOfPosts);
});
Until then, you may need to do the setTimeout approach (though it doesn't need to be a whole second).在那之前,您可能需要执行 setTimeout 方法(尽管它不需要是一整秒)。
PS I know there are better ways to do this, but I am working inside a third party environment and am pretty limited to what I have access to.
PS 我知道有更好的方法可以做到这一点,但我在第三方环境中工作,并且非常受限于我可以访问的内容。
Yeah, if you can do something else that would probably be better.是的,如果你能做点别的事情可能会更好。 Most of the time, if you want to deliberately unmount/remount a component, that is best achieved by using a
key
which you change when you want the remount to happen.大多数情况下,如果您想故意卸载/重新安装组件,最好使用您希望重新安装时更改的
key
来实现。
const [key, setKey] = useState(0);
const [allPosts, setAllPosts] = useState([]);
// ...
setKey(prev => prev + 1);
setAllPosts(newArrayOfPosts);
// ...
return (
<SomeComponent key={key} posts={allPosts} />
)
This is how you can do it -这就是你可以做到的 -
import { flushSync } from 'react-dom';
const handleClick = () => {
flushSync(() => {
setAllPosts(undefined);
// react will create a re-render here
});
flushSync(() => {
setAllPosts(newArrayOfPosts);
// react will create a re-render here
});
};
This is used to un-batch the react states.这用于取消批处理反应状态。 This is just a single way of doing it.
这只是一种方法。 The other way could be to use
setTimeout
.另一种方法可能是使用
setTimeout
。 Please note that with version 18 of react, state updates within setTimeouts are also being batched - this is known as Automatic Batching, but we still can achieve this by using different setTimeouts -请注意,在第 18 版的 react 中,setTimeouts 中的状态更新也被批处理——这被称为自动批处理,但我们仍然可以通过使用不同的 setTimeouts 来实现这一点——
const handleClick = () => {
setTimeout(() => {
setAllPosts(undefined);
// react will create a re-render here
}, 10);
setTimeout(() => {
setAllPosts(newArrayOfPosts);
// react will create a re-render here
},20);
};
Just make sure to keep a time difference to rule out the batching done by React.只要确保保持时间差以排除 React 完成的批处理。
Occasionally I may want to unmount and remount a component with new data inside it.
有时我可能想卸载并重新安装一个组件,其中包含新数据。
It sounds like this use-case calls for a useEffect()
with a dependency based on something you care about, like another piece of state or prop being provided to this component.听起来这个用例调用了一个
useEffect()
,它具有基于您关心的东西的依赖关系,例如向该组件提供的另一块状态或道具。
useEffect(() => {
setAllPosts(newArrayOfPosts);
}, [shouldUpdate]);
I've even seen examples of people triggered useEffect()
with a dependency of a piece of state called count
or renderCount
.我什至见过人们触发
useEffect()
的例子,它依赖于一个称为count
或renderCount
的状态。 Not sure if this is necessarily best practice but it's one way to go about things.不确定这是否一定是最佳实践,但这是处理事情的一种方式。
const [count, setCount] = useState(0);
const [allPosts, setAllPosts] = useState([]);
useEffect(() => {
setAllPosts(props.values);
}, [count]);
const handleChange = () => {
setCount(prevCount => prevCount + 1); // This will trigger your useEffect when handleChange() in invoked
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.