【发布时间】:2020-01-27 12:22:50
【问题描述】:
来自 React DOCS:
https://reactjs.org/docs/state-and-lifecycle.html
状态更新可能是异步的
React 可以将多个 setState() 调用批处理到单个更新中以提高性能。
这完全有道理。如果您有类似下面的函数,那么在每个setState 调用上重新渲染效率会非常低
const [state1,setState1] = useState(false);
const [state2,setState2] = useState(false);
const [state3,setState3] = useState(false);
function handleClick() {
setState1(true);
setState2(true);
setState3(true);
}
因此,在上述情况下,我希望 React 将所有 3 个 setState 调用批处理到一个重新渲染中。它就是这样做的!
但我想知道的是:
一旦handleClick 完成,是否保证重新渲染立即 handleClick 已经完成运行?我的意思是立即,比如立即同步?
从我构建的这个 sn-p 看来,这是真的。在handleClick 完成后,React 将同步应用更新(重新渲染)。如果我的假设有误,请纠正我。
见下面的sn-p:
- 尽可能快地点击 3 倍
-
handleClick将调用setState并将记录当前的props.counter -
App上有一个昂贵的循环,因此重新渲染需要很长时间 - 您的点击速度将比 React 重新渲染整个应用程序的速度快得多
- 但是你会看到
props.counter每次都不一样,没有任何重复,即使你点击多次真的很快 - 这意味着一旦你的第二次点击被处理(这将需要一段时间,因为昂贵的循环),React 已经重新渲染了整个事情,
handleClick函数已经用 @ 的新值重新创建了来自counter更新状态的 987654334@。 - 尝试快速点击 5 次,您会发现行为是一样的。
问题
当setState 在事件处理函数内部进行调用时,一旦该处理函数完成运行,是否可以保证在处理函数完成后立即(同步)重新呈现?
function App() {
console.log("App rendering...");
const [counter, setCounter] = React.useState(0);
// AN EXPENSIVE LOOP TO SLOW DOWN THE RENDER OF 'App'
for (let i = 0; i < 100000; ) {
for (let j = 0; j < 10000; j++) {}
i = i + 1;
}
return <Child counter={counter} setCounter={setCounter} />;
}
function Child(props) {
console.log("Child rendering...");
// THIS FUNCTION WILL CALL 'setState'
// AND WILL ALSO LOG THE CURRENT 'props.counter'
function handleClick() {
props.setCounter(prevState => prevState + 1);
console.log(props.counter);
}
return (
<React.Fragment>
<div>Counter: {props.counter}</div>
<button onClick={handleClick}>Click</button>
</React.Fragment>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
【问题讨论】:
标签: javascript reactjs react-hooks setstate