为何React父组件状态已更新,increment函数中状态仍未改变?
为何React组件状态更新后,定时器里的状态还是旧值?
这本质是JavaScript闭包结合React渲染快照特性导致的,具体拆解如下:
闭包捕获的是渲染快照里的状态
每次React组件渲染时,会生成一个包含当前状态的快照,组件内的所有函数(比如increment)都会捕获这个快照里的状态值。你第一次点击按钮时,组件处于初始渲染状态,count=0,此时创建的increment函数会牢牢抓住这个0。因为
setTimeout是异步任务,会在2秒后才执行回调,而这时候哪怕组件已经因为状态更新重新渲染了,之前创建的increment函数里的count依然是它被创建时捕获的那个初始值0——闭包不会自动同步后续的状态变化。快速点击多次复用了同一个闭包
你快速点击3次按钮时,这3次点击触发的increment都是第一次渲染时生成的那个函数(因为组件还没来得及重新渲染),所以这三个异步回调都捕获了同一个count=0。对应你的控制台输出:
- 第一个定时器回调触发,执行
setCount(0+1),组件重新渲染,count变为1,打印DelayedCounter 1; - 第二个定时器回调触发,依然用
count=0执行setCount(0+1),此时状态从1变成1,值没有变化,React不会触发重渲染; - 第三个定时器同理,还是用
count=0,同样不会触发重渲染。
- 第一个定时器回调触发,执行
所以你会看到三次increment 0,但只有两次DelayedCounter 1。
你提到的用prevState回调是正确的解决方案:
setCount(prevCount => prevCount + 1)
这种方式下,React会把当前最新的状态值传递给回调函数,完全避开闭包捕获旧值的问题,确保每次更新都是基于最新状态。
内容的提问来源于stack exchange,提问作者Franky1790
相关产品推荐
相关产品推荐

