React useEffect实现计数器:两段代码差异及第一段失效原因咨询
React useEffect计数器代码差异及第一段失效原因分析
第一段代码为何无法正常工作
先看第一段代码:
function IntervalHookCounter() { const [count,setCount] = useState(0) useEffect(()=>{ const interval = setInterval(tick,1000) },[]) const tick = ()=>{ setCount(count+1) } }
问题出在闭包和状态更新方式的组合上:
useEffect的依赖是[],说明这个effect只会在组件首次挂载时执行一次,创建的定时器会一直引用挂载时的tick函数。- 挂载时
tick里的count是闭包捕获的初始值0,之后不管组件状态怎么更新,这个闭包里的count永远是0。所以每次定时器触发tick,执行的都是setCount(0+1),count会被设置为1,但后续再触发时,还是用0来计算,结果还是1,界面就停在1不再变化了。
两段代码的核心差异
第二段代码:
function IntervalHookCounter() { const [count,setCount] = useState(0) useEffect(()=>{ const interval = setInterval(tick,1000) },[]) const tick = ()=>{ setCount(prevState=>prevState+1) } }
两段的唯一区别是setCount的调用方式:
- 第一段用的是直接基于当前变量值更新:
setCount(count+1),依赖的是闭包中的count值,一旦闭包捕获的是旧值,更新就会出错。 - 第二段用的是函数式更新:
setCount(prevState=>prevState+1),这种方式下,React会自动把当前最新的状态值作为参数传给回调函数,不管闭包里的count是什么旧值,都能拿到最新的状态来计算下一个值,所以定时器每次触发都能正确让count加1,计数器正常工作。
内容的提问来源于stack exchange,提问作者Nomear77
相关产品推荐
相关产品推荐

