说说 React 中的 setState 执行机制
一、是什么
setState 是 React 中更新组件状态并触发重新渲染的核心机制。在类组件中通过 this.setState() 调用,在函数组件中通过 useState 返回的 setter 函数调用。
理解 setState 的执行机制,特别是它的同步/异步行为和批处理策略,是深入理解 React 更新流程的关键。
二、类组件中的 setState
2.1 基本用法
2.2 状态合并
类组件的 setState 会将传入的对象与当前 state 进行浅合并(Shallow Merge):
2.3 连续调用的问题
三、React 18 之前的批处理行为
在 React 18 之前,setState 的批处理行为取决于调用时机:
3.1 React 事件处理中——异步批处理
3.2 非 React 上下文中——同步执行(React 18 之前)
这种不一致的行为是 React 17 及之前版本的一个痛点,开发者需要判断执行上下文才能预测 setState 的行为。
四、React 18 的自动批处理
React 18 引入了 Automatic Batching(自动批处理),无论在什么上下文中,多次 setState 都会被自动批处理:
前提条件:使用 createRoot API 而非旧的 ReactDOM.render。
4.1 flushSync 退出批处理
如果确实需要立即执行更新(极少见),可以使用 flushSync:
flushSync 的使用场景非常有限,主要用于需要在两次状态更新之间读取 DOM 的情况。
五、函数组件中的 useState
5.1 基本机制
与类组件不同,函数组件中的 state 是闭包捕获的快照,而不是 this.state 引用:
如果需要获取最新值,使用 useRef:
5.2 状态替换 vs 状态合并
5.3 惰性初始化
当初始 state 的计算比较昂贵时,使用函数形式的初始值:
六、更新优先级
React 18 并发模式下,可以通过 useTransition 和 useDeferredValue 标记低优先级更新。高优先级更新(如用户输入)会打断低优先级更新的渲染,保证交互即时响应。startTransition 中的 setState 会被标记为可中断的低优先级更新。
七、总结
面试核心要点:
- React 18 实现了全场景自动批处理
- 函数式更新
setState(prev => ...)能保证基于最新值更新 - 函数组件的 state 是闭包快照,类组件的
this.state是引用 flushSync可以退出批处理(极少使用)- 惰性初始化避免昂贵计算的重复执行