React,无法访问传递给 useEffect() 中的 setInterval() 的函数内部状态变量的更新值
React, can't access updated value of state variable inside function passed to setInterval() in useEffect()
我正在使用 React 构建一个简单的时钟应用程序。目前 countDown()
功能有效,但我希望用户能够通过按下按钮 stop/start 时钟。我有一个名为 paused
的状态布尔值,当用户单击按钮时它会反转。麻烦的是,paused
的值反转后,传递给setInterval()
的countDown()
函数内部对paused
的引用似乎正在访问[=12的默认值=],而不是更新后的值。
function Clock(){
const [sec, setSecs] = useState(sessionLength * 60);
const [paused, setPaused] = useState(false);
const playPause = () => {
setPaused(paused => !paused);
};
const countDown = () => {
if(!paused){
setSecs(sec => sec - 1)
}
}
useEffect(() => {
const interval = setInterval(() => {
countDown();
}, 1000);
return () => {
clearInterval(interval);
};
}, []);
我假设它与 React 中调用 setState()
的异步性质有关,and/or 使用正则表达式时 scoping/context 的性质。但是,我无法通过阅读与这些概念相关的文档来确定发生了什么。
我可以想出一些解决方法来让我的应用程序按预期运行。但是我想了解我当前的方法有什么问题。我将不胜感激,任何人都可以对此有所启发!
在您的代码中,useEffect
在安装组件时仅被调用一次。
里面注册的倒计时函数在调用useEffect/setInterval
时会有初始值。所以 paused
只会在您最初安装组件时具有值。因为您没有直接调用 countDown 或在 useEffect
中更新它的值,所以它没有更新。
我认为你可以这样解决这个问题:
interval.current = useRef(null);
const countDown = () => {
if(!paused){
setSecs(sec => sec - 1)
}
}
useEffect(() => {
clearInterval(interval.current);
interval.current = setInterval(countDown, 1000);
return () => {
clearInterval(interval.current);
};
}, [paused]);
您的 useEffect
取决于 paused
的值,因为它需要创建一个新的间隔(具有不同的倒计时功能)。这不仅会在挂载时触发 useEffect
,还会在每次 paused
更改时触发。因此,一种解决方案是清除间隔并启动一个具有不同回调函数的新间隔。
编辑:你实际上可以改进它,因为你只希望间隔为 运行 如果 countDown 函数确实做了一些事情,所以这也应该有效:
useEffect(() => {
clearInterval(interval.current);
if(!paused) {
interval.current = setInterval(countDown, 1000);
}
return () => {
clearInterval(interval.current);
};
}, [paused]);
我正在使用 React 构建一个简单的时钟应用程序。目前 countDown()
功能有效,但我希望用户能够通过按下按钮 stop/start 时钟。我有一个名为 paused
的状态布尔值,当用户单击按钮时它会反转。麻烦的是,paused
的值反转后,传递给setInterval()
的countDown()
函数内部对paused
的引用似乎正在访问[=12的默认值=],而不是更新后的值。
function Clock(){
const [sec, setSecs] = useState(sessionLength * 60);
const [paused, setPaused] = useState(false);
const playPause = () => {
setPaused(paused => !paused);
};
const countDown = () => {
if(!paused){
setSecs(sec => sec - 1)
}
}
useEffect(() => {
const interval = setInterval(() => {
countDown();
}, 1000);
return () => {
clearInterval(interval);
};
}, []);
我假设它与 React 中调用 setState()
的异步性质有关,and/or 使用正则表达式时 scoping/context 的性质。但是,我无法通过阅读与这些概念相关的文档来确定发生了什么。
我可以想出一些解决方法来让我的应用程序按预期运行。但是我想了解我当前的方法有什么问题。我将不胜感激,任何人都可以对此有所启发!
在您的代码中,useEffect
在安装组件时仅被调用一次。
里面注册的倒计时函数在调用useEffect/setInterval
时会有初始值。所以 paused
只会在您最初安装组件时具有值。因为您没有直接调用 countDown 或在 useEffect
中更新它的值,所以它没有更新。
我认为你可以这样解决这个问题:
interval.current = useRef(null);
const countDown = () => {
if(!paused){
setSecs(sec => sec - 1)
}
}
useEffect(() => {
clearInterval(interval.current);
interval.current = setInterval(countDown, 1000);
return () => {
clearInterval(interval.current);
};
}, [paused]);
您的 useEffect
取决于 paused
的值,因为它需要创建一个新的间隔(具有不同的倒计时功能)。这不仅会在挂载时触发 useEffect
,还会在每次 paused
更改时触发。因此,一种解决方案是清除间隔并启动一个具有不同回调函数的新间隔。
编辑:你实际上可以改进它,因为你只希望间隔为 运行 如果 countDown 函数确实做了一些事情,所以这也应该有效:
useEffect(() => {
clearInterval(interval.current);
if(!paused) {
interval.current = setInterval(countDown, 1000);
}
return () => {
clearInterval(interval.current);
};
}, [paused]);