React 19 入门教程
State 作为快照
本教程共 50 篇 · 第 16 篇 · 更新于 2026-07-29 · 约 7 分钟阅读
React状态快照批处理函数式更新异步更新
16. State 作为快照
本节目标:理解状态在单次渲染中是不变的”快照”,掌握批处理和函数式更新,避免状态更新中的常见陷阱。
状态在渲染中是不变的
调用 setCount 不会立刻改变 count 的值。它请求 React 在下次渲染时使用新值:
function Counter() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
console.log(count); // 还是旧值!不是 +1 后的
}
return <button onClick={handleClick}>{count}</button>;
}
第一次点击,setCount(1) 被调用,但 console.log 打印的还是 0。
每次渲染中的状态是固定的快照,就像照片里的人不会突然变老。
批处理:多次 setState 合并
连续调用两次 setCount,不会渲染两次:
function Counter() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
setCount(count + 1);
// count 从 0 变成 1,不是 2
}
return <button onClick={handleClick}>{count}</button>;
}
两次 setCount 都基于同一次渲染的快照(count = 0),所以结果还是 1。
什么是批处理
React 会把同一个事件处理函数里的多个 setState 合并成一次渲染。这是性能优化,避免不必要的重复渲染。
函数式更新:基于前一个状态
想让计数器连加两次?用函数式更新:
function Counter() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(prev => prev + 1);
setCount(prev => prev + 1);
// count 从 0 变成 2
}
return <button onClick={handleClick}>{count}</button>;
}
setCount(prev => prev + 1) 里的 prev 是 React 保证的最新状态值。两次调用依次执行:0→1→2。
什么时候用函数式更新
新状态依赖旧状态时,一律用函数式更新。不依赖旧状态时,直接传值就行。
一个完整的例子
function Counter() {
const [count, setCount] = useState(0);
function handleIncrement() {
setCount(prev => prev + 1);
}
function handleDecrement() {
setCount(prev => prev - 1);
}
function handleReset() {
setCount(0); // 不依赖旧值,直接传
}
return (
<div>
<p>{count}</p>
<button onClick={handleIncrement}>+1</button>
<button onClick={handleDecrement}>-1</button>
<button onClick={handleReset}>重置</button>
</div>
);
}
对象和数组的状态更新
直接修改对象不会触发渲染,必须传入新引用:
function Form() {
const [person, setPerson] = useState({ name: '', age: 0 });
// 错误:直接修改
// person.name = '张三';
// 正确:传入新对象
setPerson({ ...person, name: '张三' });
}
不要直接修改状态
person.name = '张三'不会触发渲染。React 通过引用比较判断状态是否变化,直接修改原对象引用不变。
状态更新的时间线
用户点击 → 事件处理函数执行 → 多个 setState 被调用
→ React 批处理,合并更新 → 重新渲染 → 页面更新
整个过程是异步的。setState 调用后,状态不会立即变化。
React 18+ 自动批处理
React 18 之前,只有事件处理函数里的 setState 会被批处理。Promise、setTimeout 里的不会。React 18 之后全部自动批处理。
本节要点
- 单次渲染中状态是固定快照
- 批处理合并多个 setState 为一次渲染
- 新状态依赖旧状态时用函数式更新
prev => prev + 1 - 不要直接修改对象/数组状态,要传入新引用