为什么React中setInterval触发useState递增时,打印值始终为0?
问题原因分析
核心原因是React函数组件的闭包捕获特性,具体逻辑如下:
- 你的
useEffect依赖项是空数组,所以这个副作用只会在组件首次挂载时执行1次,后续组件重渲染都不会再运行。 - 首次渲染时,
inc的初始值是0,定时器的回调函数在这一刻被创建,闭包捕获了当前作用域下的inc = 0这个值。 - 你调用
setInc时用了函数式更新写法prevState => prevState +1,这个更新逻辑是从React内部维护的最新状态快照取值计算,所以状态inc本身是能正常递增的,只是定时器回调始终拿着首次渲染时捕获的旧inc值,所以每次打印都是0。
两种常用解决方案
方案1:将inc加入useEffect依赖数组
把inc加入依赖后,每次inc变化都会重新执行副作用:销毁旧定时器、创建新定时器,新的定时器回调会捕获到最新的inc值,打印结果就正常了。
const [inc, setInc] = useState(0); useEffect(() => { const ti = setInterval(() => { setInc(prevState => prevState + 1); console.log(inc); }, 3000) return () => { clearInterval(ti); } }, [inc]);
方案2:用useRef存储最新状态
如果不想频繁销毁重建定时器,可以用useRef来同步最新的inc值,ref的current属性是可变的,不会被闭包捕获限制:
const [inc, setInc] = useState(0); const incRef = useRef(inc); // 同步最新的inc到ref useEffect(() => { incRef.current = inc; }, [inc]); useEffect(() => { const ti = setInterval(() => { setInc(prevState => prevState + 1); console.log(incRef.current); }, 3000) return () => { clearInterval(ti); } }, []);
内容的提问来源于stack exchange,提问作者Paj
相关产品推荐
相关产品推荐

