我知道 setState 是异步的,但它是否显式等待所有其他代码在完成之前执行(甚至带有延迟的 setTimeout)?
我一直在尝试使用 React 中的简单递归函数来增加计数器,但 setState 从未执行。我添加了一个延迟一秒的setTimeout,只是为了给setState足够的时间来执行,但它只是无限等待,永远不会执行。
用 useRef 替换 useState 是最好的解决方案,还是有更优雅的解决方案?
import { useState } from 'react';
const TestComponent = () => {
const [counter, setCounter] = useState(1);
const setStateTest = () => {
setCounter(prev => prev + 1); // this line of code never executes
setTimeout(() => {
if (counter < 10) {
setStateTest(); // this recursion happens infinitely because counter is never incremented
console.log(counter); // the logged value is always 1, no incrementing
}
}, 1000)
}
return <button onClick={setStateTest}>Set State Test</button>
}
不要为此使用递归。
我怀疑问题是围绕原始
counter
值的闭包。 状态本身可能正在更新,但您没有将当前状态记录到控制台。 您正在记录首次调用该函数时捕获的该状态的值。 (再次单击按钮,观察更新后的值与持续的原始值一起记录到控制台。)
不要递归,而是依靠
useEffect
。 例如,考虑这种方法:
useEffect(() => {
console.log(counter);
const x = setTimeout(() => {
setCounter(prev => prev + 1);
}, 1000);
return () => clearTimeout(x);
}, [counter]);
任何时候
counter
发生变化,该效果都会执行。 所有这些效果的作用是:
counter
的值记录到控制台然后要最初触发它,只需更新一次状态:
<button onClick={() => setCounter(prev => prev + 1)}>Set State Test</button>
一旦状态发生改变,效果就会触发,并且只要组件被加载,它就会每秒重新触发一次(通过更新其依赖数组中的状态值)。