这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战
翻译自:beta.reactjs.org/learn/queue…
设置 state 的值引起另一个 render 队列。但有时你可能希望执行下一次 render 队列之前对值执行多个操作。为了这样做,这篇文章有助于了解 React 如何批量更新状态。
你将会学习到:
- 什么是“批量处理(batching)”,React 如何使用它来处理多个 state 更新
- 如何在一行中对同样的 state 应用几个更新
系列文章
这是一个系列的文章,希望你能从头看,因为它们的例子之间会有先后关系的~
如果在替换 state 后更新 state 会发生什么
前面两篇文章我们讲了,在一个事件处理程序里,连续使用 setNumber(n+1)
的话,React 会想处理你点菜的服务员一样,只会更新一次(只点了一个菜)。但是如果更新多次的话,也是可以实现的,可以用 setNumber(n => n + 1)
这种形式,每次执行时参数 n
,都是上一次更新计算后的最新值。
那么如果我们混用这两种写法,会发生什么呢?比如下面的例子
<button onClick={() => {
setNumber(number + 5);
setNumber(n => n + 1);
}}>
复制代码
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 5);
setNumber(n => n + 1);
}}>Increase the number</button>
</>
)
}
复制代码
发现点完按钮后 number +6 了,这是为什么呢?
下面是事件处理程序告诉 React 做的事情:
setNumber(number + 5)
:number
是0
, 于是setNumber(0 + 5)
. React 把 “替换为5
” 增加到它的队列里。setNumber(n => n + 1)
:n => n + 1
是一个更新函数。 React 将这个函数添加到其队列中。
在下一次渲染期间,React 会遍历 state 队列:
更新队列 | n |
返回值。 |
---|---|---|
“替换为 5 ” |
0 (未使用) |
5 |
n => n + 1 |
5 |
5 + 1 = 6 |
React 将 6 存储为最终结果并从 useState
返回它。
您可能已经注意到 setState(x)
实际上与 setState(n => x)
类似,但 n
未使用到!
如果在更新 state 后替换 state 会发生什么
和上面的例子相反,这次我们先更新 state
<button onClick={() => {
setNumber(number + 5);
setNumber(n => n + 1);
setNumber(42);
}}>
复制代码
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 5);
setNumber(n => n + 1);
setNumber(42);
}}>Increase the number</button>
</>
)
}
复制代码
下面是 React 在执行这个事件处理程序时如何通过这些代码行工作:
setNumber(number + 5)
:number
值是0
, 于是setNumber(0 + 5)
. React 把 “替换为5
” 放入它的队列中。setNumber(n => n + 1)
:n => n + 1
是一个更新函数。 React 将这个函数添加到其队列中。setNumber(42)
: React 把 “替换为42
” 放入它的队列中。
在下一次渲染中,React 通过 state 队列:
更新队列 | n |
返回值 |
---|---|---|
“替换为 5 ” |
0 (未使用) |
5 |
n => n + 1 |
5 |
5 + 1 = 6 |
“替换为 42 ” |
6 (未使用) |
42 |
然后 React 存储 42 作为最终结果并从 useState
返回。
总结
总而言之,您可以通过以下方式思考传递给 setNumber
state setter 的内容:
- 更新函数(例如 n => n + 1),会被添加到队列中。
- 任何其他值(例如数字 5)都会将“替换为 5”添加到队列中,并会忽略已经排队的内容。
事件处理程序完成后,React 将触发重新渲染。在重新渲染期间,React 将处理队列。更新程序功能在渲染期间运行,所以更新函数必须是纯函数(pure function)并且只返回结果。不要尝试从它们内部设置状态或运行其他副作用。严格模式下,React 会运行每个更新器函数两次(但丢弃第二个结果)以帮助您发现错误。