You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactJS中状态时变问题:进度值无法正常递增的排查与解决

React状态更新异常:progressValue始终显示0的问题分析

我希望在React中每500毫秒将状态值progressValue从0递增到100,为此编写了如下代码:

const [progressValue, setProgressValue] = React.useState<number>(0)

const tick = () => {
    console.log("progressValue: " + progressValue)
    if (progressValue >= 100) {
        setProgressValue(100)
    } else {
        const newValue = progressValue + 0.1
        setProgressValue(newValue)
        setTimeout(tick, 500)
    }
}

const onPlayClicked = () => {
    setProgressValue(0)
    tick()
}

但控制台日志始终输出:

progressValue: 0
progressValue: 0
progressValue: 0
...

问题原因

这是因为闭包捕获了过期的状态值。当调用onPlayClicked时,tick函数被创建,此时它捕获的progressValue是初始值0。之后每次通过setTimeout调用tick时,这个函数依然引用的是最初捕获的那个progressValue,永远为0。所以每次都会执行newValue = 0 + 0.1,并再次设置定时器,导致日志一直输出0。


解决方法(用户最终实现)

最终通过以下代码解决了该问题:

const [progressValue, setProgressValue] = React.useState<number>(0)

React.useEffect(() => {
    const interval = setInterval(() => {
        if (progressValue < 100) {
            setProgressValue((prevVal) => prevVal + 1);
        }
    }, 500);
    return () => clearInterval(interval);
}, [progressValue]);

解决思路解析

  • 使用setInterval替代嵌套的setTimeout,避免重复创建闭包捕获旧状态
  • 调用setProgressValue时采用函数式更新:(prevVal) => prevVal + 1,这种方式能确保每次获取到的是最新的状态值,不受闭包影响
  • 通过useEffect监听progressValue的变化,状态更新时自动销毁旧定时器并创建新定时器(注:如果仅使用函数式更新,也可以将依赖数组设为空,只在组件挂载时创建一次定时器,进一步优化性能)

内容的提问来源于stack exchange,提问作者Benvorth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 19:53:16