第 02 节:连续更新为什么会挤在同一个旧值上
本节目标:
- 解释为什么
setCount(count + 1)连写两次可能只加 1 。- 使用函数式更新让每次更新基于上一版 state。
- 修掉一个“目标加 2,结果只加 1”的按钮。
两次调用不等于读到两个新值
React 会等事件处理函数里的代码跑完,再处理 state 更新队列1。如果你在同一次点击里连写两次 setCount(count + 1),这两个表达式读到的可能都是同一个旧 count。
这里的关键不是“React 慢”,而是“你读到的是本次渲染里的值”。如果两次都从旧值 0 算 0 + 1,最后就不是 2 。
讲解
React 文档给了一个专门的写法:把函数传给 setter,例如 setNumber(n => n + 1)。这个函数会在处理队列时拿到上一版 state,再算下一版1。
可以把 c => c + 1 读成“别用我现在闭包里看到的旧 count,等 React 处理队列时,把上一版 state 交给我”。这就是函数式更新。
跟我做一遍
坏掉的版本:
如果点击前 count 是 0,两行都读到 0,两行都请求下一次变成 1 。修法是:
这张表先把坏现象钉住:两行不是接力从 0 到 1 再到 2,而是都拿同一个旧值算。下面才进入修法。
第一条 updater 从 0 算到 1,第二条 updater 从上一条结果 1 算到 2 。这里的“上一条结果”来自更新队列,不是来自你手动改了 count 变量。
换你补全
把下面两行补成函数式更新:
参考答案:
留空点不在变量名,而在“把一个 updater 函数交给 setter”这个机制。
小结 + 通向下一节
连续 state 更新最稳的写法是 updater 函数,因为它让每一步基于上一版 state。下一节把这个计数器放进 Next.js:按钮能动还需要一个 Client Component 边界。
Footnotes
-
React Learn: Queueing a Series of State Updates — https://react.dev/learn/queueing-a-series-of-state-updates ↩ ↩2
Exercises
写一段解释,说明为什么 setCount(count + 1) 连写两次容易只加 1 。
把“加 3”按钮写成函数式更新版本。
- example为什么普通变量不行:一个反例