问题是在 setInterval 回调中,count 的值没有改变,因为我们创建了一个闭包,其中 count 的值设置为 0,就像效果回调运行时一样
第一次渲染时,闭包 log() 将 count 变量捕获为 0。之后,即使 count 增加,log() 仍然使用初始渲染时的 count 为 0。 log() 是一个过时的闭包。
解决方案是让useEffect()知道闭包log()依赖于count并正确处理interval的重置:
在 useEffect 中添加 count 作为依赖项
useEffect(() => {
const id = setInterval(innerFunction(), 1000);
return () => clearInterval(id);
}, [count]);
正确设置依赖项后,一旦计数发生变化,useEffect() 就会更新闭包。
解释
在没有依赖关系的情况下, useEffect() 仅在最初被调用。它不会被重新调用。
useEffect(() => {
console.log("is re-rendering");
const id = setInterval(innerFunction(), 1000);
return () => clearInterval(id);
}, []);
Here, "正在重新渲染" 只记录一次。
如果您使用此语法而不是函数语法(获取最新计数状态)来设置状态。它还将行为显示为过时关闭的日志
setCount( count + 1); //always 1 as it gets 0 as count value
Since 使用效果之后没有被调用count更改时,它们采用相同的初始输入并给出相同的初始输出,因为它们不知道更改。
如果我们添加 count 作为依赖项 then 使用效果每当count值的变化和设置时间间隔也使用新的更新输入重新初始化。
更多信息
https://dmitripavlutin.com/react-hooks-stale-closures/
https://reactjs.org/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependency-change-too-often
Example
我已经用简单的例子展示了类似的问题。
在这里,我改变了outerVar的值(让我们认为它就像一个count状态)在第一次调用outerfn之后。
但其更新的变化并未体现出来。这就是闭包的工作原理。
let outerVar='initial-outer'
function outerfn(outerVar){
return function innerfn(innerVar){
console.log('outer variable: '+ outerVar)
console.log('inner variable: '+ innerVar)
}
}
let newfn=outerfn(outerVar)
outerVar="updated-outer" // outerVal is now changed
newfn('inside') // but initial outerVal is printed here
newfn=outerfn(outerVar)//resetting closure with updated value (like adding dependency to useEffect)
newfn('inside') // updated outerVal is printed now