Skip to content
字数
1027 字
阅读时间
4 分钟

React 中状态更新的合并机制和 flushSync 的工作原理,本质上与 React 的更新调度机制批量更新策略相关。我们可以从底层逻辑拆解:

一、同步状态更新被合并的原理:批量更新(Batching)

React 为了避免频繁渲染导致的性能问题,会将同一事件循环中的多个状态更新合并为一次渲染,这个过程称为“批量更新”。

具体逻辑:

  1. 更新队列(Update Queue)
    当调用 setState(或 useState 的更新函数)时,React 不会立即更新状态并触发渲染,而是将这次更新放入一个“更新队列”中。

  2. 批量处理时机
    React 会在当前代码执行上下文(如事件处理函数、useEffect 回调等)执行完毕后,统一处理队列中的所有更新:

    • 先计算所有状态的最终值(比如多次更新同一状态时,取最后一次的结果;更新不同状态时,合并成一个新的状态对象)。
    • 然后只触发一次组件渲染,使用合并后的最终状态。
  3. 为什么 useEffect 中同步更新会被合并?
    useEffect 的回调函数属于 React 可控制的“合成事件/生命周期上下文”,React 会在此类上下文中自动启用批量更新。因此,即使在 useEffect 中同步调用多次 setXxx,也会被放入同一个更新队列,最终合并为一次渲染。

二、flushSync 做了什么?强制立即执行更新

flushSync 是 React 18 引入的 API,作用是打破批量更新机制,强制让当前更新队列中的所有更新立即执行,并同步触发渲染

具体操作:

1.** 暂停批量更新 **:flushSync 会临时关闭 React 的批量更新开关,告诉 React“这次更新必须立即处理,不能等待”。

2.** 同步执行更新队列 **:flushSync 内部的状态更新会被立即加入更新队列,并强制 React 同步处理队列中的所有更新(包括之前可能积累的未处理更新)。

3.** 触发渲染 **:更新处理完成后,会立即触发组件渲染,确保状态的变化同步反映到 DOM 上。

4.** 恢复批量更新 **:执行完毕后,React 会恢复批量更新机制,不影响后续代码的默认行为。

举个形象的例子:

可以把 React 的批量更新比作“快递柜”:

  • 平时,你(状态更新)会把快递(更新任务)放进柜子,快递员(React)会等柜子满了(当前上下文执行完)再一次性取走派送(合并渲染)。
  • flushSync 相当于你直接给快递员打电话:“这个快递必须现在送!”,快递员会立即过来取走这个快递(以及柜子里可能有的其他快递),当场派送(同步渲染)。

关键区别总结:

场景批量更新?渲染时机适用场景
普通同步状态更新当前上下文执行完后合并渲染绝大多数情况,优化性能
flushSync 包裹的更新立即执行并同步渲染必须立即看到更新的场景(罕见)

注意:

flushSync 会破坏 React 的性能优化,可能导致额外的渲染,甚至引发布局抖动(因为同步渲染会立即操作 DOM)。因此,只有在必须让状态更新同步生效的场景下使用(例如:需要立即读取更新后的 DOM 信息),其他情况应依赖 React 的默认批量更新。

贡献者

The avatar of contributor named as jiechen jiechen

页面历史

撰写