也许 state 变量看起来和一般的可读写的 JavaScript 变量类似。但 state 在其表现出的特性上更像是一张快照。设置它不会更改你已有的 state 变量,但会触发重新渲染。


React 会对 state 更新进行批处理

点击按钮后,number 的值为 3。
这是因为 useState 的更新是异步的,且在同一个事件处理函数中多次调用 setNumber 时,React 会进行批量更新。最终只会执行一次更新,将 number 从 0 增加到 1。
虽然代码中调用了三次 setNumber(number + 1),但由于 React 的批处理机制,只有最后一次更新会被应用,因此 number 的值会增加 1 而不是 3。
如果希望每次点击都增加 3,可以使用函数式更新来确保每次更新都能正确地基于当前状态进行计算。
在下次渲染前多次更新同一个 state
这是一个不常见的用例,但是如果你想在下次渲染之前多次更新同一个 state,你可以像 setNumber(n => n + 1) 这样传入一个根据队列中的前一个 state 计算下一个 state 的 函数,而不是像 setNumber(number + 1) 这样传入 下一个 state 值。这是一种告诉 React “用 state 值做某事”而不是仅仅替换它的方法。
现在尝试递增计数器:

在这里,n => n + 1 被称为 更新函数。当你将它传递给一个 state 设置函数时:
React 会将此函数加入队列,以便在事件处理函数中的所有其他代码运行后进行处理。
在下一次渲染期间,React 会遍历队列并给你更新之后的最终 state。
setNumber(n => n + 1);
setNumber(n => n + 1);
setNumber(n => n + 1);
下面是 React 在执行事件处理函数时处理这几行代码的过程:
setNumber(n => n + 1):n => n + 1 是一个函数。React 将它加入队列。
setNumber(n => n + 1):n => n + 1 是一个函数。React 将它加入队列。
setNumber(n => n + 1):n => n + 1 是一个函数。React 将它加入队列。
当你在下次渲染期间调用 useState 时,React 会遍历队列。之前的 number state 的值是 0,所以这就是 React 作为参数 n 传递给第一个更新函数的值。然后 React 会获取你上一个更新函数的返回值,并将其作为 n 传递给下一个更新函数,以此类推:

React 会保存 3 为最终结果并从 useState 中返回。

这是事件处理函数告诉 React 要做的事情:
setNumber(number + 5):number 为 0,所以 setNumber(0 + 5)。React 将 “替换为 5” 添加到其队列中。
setNumber(n => n + 1):n => n + 1 是一个更新函数。 React 将 该函数 添加到其队列中。

以下是 React 在执行事件处理函数时处理这几行代码的过程:
setNumber(number + 5):number 为 0,所以 setNumber(0 + 5)。React 将 “替换为 5” 添加到其队列中。
setNumber(n => n + 1):n => n + 1 是一个更新函数。React 将该函数添加到其队列中。
setNumber(42):React 将 “替换为 42” 添加到其队列中。
总而言之,以下是你可以考虑传递给 setNumber state 设置函数的内容:
一个更新函数(例如:n => n + 1)会被添加到队列中。
任何其他的值(例如:数字 5)会导致“替换为 5”被添加到队列中,已经在队列中的内容会被忽略。
浙公网安备 33010602011771号