经典示例,并不清楚为什么具有直接值的 setter 不起作用 setCount(count+1) 应用程序仅包含 1 并停止计数,但是每秒都会调用间隔函数,如果我们放置日志,我们就可以看到它。
const { useState, useEffect } = React;
const Counter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => setCount(count+1), 1000);
// this set count works
// const id = setInterval(() => setCount(c => c + 1), 1000);
return () => clearInterval(id);
}, []);
return (<div>{count}<button onClick={()=>setCount(10)}>Give10</button></div>);
};
ReactDOM
.createRoot(root)
.render(<Counter/ >);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
count
问题是,每次间隔到达时,在 useEffect 箭头函数中捕获的值都具有相同的 0 值,因此实际上每一秒您都会将状态设置为 1,即0+1
。原因是效果仅在第一次渲染时运行一次。这是由于您如何编程要调用的效果 - 第二个 useEffect 的参数是,[]
其字面意思是“在第一次渲染时从第一个参数运行一次函数”。您可以在以下问题的答案中阅读可用的替代方案:每秒更新 useEffect 中的状态,持续 10 秒
你应该记住的一件事是,闭包内的 count 值不会在每次渲染时自动更新,但从第一次执行开始,闭包将始终看到 count 的值。因此 setCount(1) 将始终被重复调用,因为 count + 1 将得到 1,这意味着计数器将不再递增
解决您的问题
在您的效果中,您正在使用回调来调用 setInterval,该回调接收初始计数值 0 和 setCount 函数。当您增加状态时,setInterval 不会收到更新的计数状态(因为您已将参数传递给 setInterval 一次)。
另一方面,setState 期望一个新值或一个接收先前值的回调函数。