【react18原理探究实践】更新调度的完整流程

🧑‍💻 写在开头

之前写了几篇关于react的原理文章,但是后面比较忙就没有后续了,最近在准备面试,做编辑器的时候用到了自定义渲染器,在以前的时候我看过react原理的很多文章,一直想总结成自己的文章方便复习,现在又重新捡起来,继续往下写

点赞 + 收藏 === 学会 🤣🤣🤣

在使用 React 的时候,我们经常会写这样的代码:

ini 复制代码
setCount(c => c + 1);
setCount(c => c + 1);

最终结果 count 只更新一次,但值却正确地加了 2。这背后涉及到 React 的 Update 对象UpdateQueue 队列调度机制 以及 批量更新

本文就带你从源码角度完整梳理一遍 React 更新的完整流程,并解释为什么 React17 里 setTimeout/Promise 不是批量的,而 React18 却可以自动批量。


🥑 你能学到什么?

读完这篇文章,你将收获:

  • Update 对象的结构和作用
  • UpdateQueue 如何统一管理更新
  • React 更新的四个阶段:触发 → 调度 → render → commit
  • 批量更新的本质
  • 为什么 React17 里异步更新不是批量的,而 React18 变了
  • isBatchingUpdates 这个标志位到底在什么时候是 true

✍️系列文章react实现原理系列

一、Update 对象

每次调用 setStatedispatch,React 内部都会生成一个 Update 对象

js 复制代码
export type Update<State> = {
  eventTime: number,              // 事件触发时间
  lane: Lane,                     // 优先级
  tag: 0 | 1 | 2 | 3,             // 更新类型(更新/替换/强制/捕获)
  payload: any,                   // 载荷,可能是值,也可能是函数
  callback: (() => void) | null,  // 更新完成后的回调
  next: Update<State> | null,     // 指向下一个 update,形成链表
};

关键点:

  • Update 不是直接存新值,而是存一条"指令" → 最终 state 如何计算。
  • setState(1) → payload 是值
  • setState(prev => prev + 1) → payload 是函数
  • forceUpdate() → payload 为空

👉 这样 React 就能先把更新收集起来,最后统一计算。


二、UpdateQueue 更新队列

每个 Fiber 节点都有一个 updateQueue,用链表保存挂在该组件上的所有更新。

  • 多次 setState → 会依次挂多个 Update。
  • 在 render 阶段统一处理这些更新,得到新的 state。

这就解释了为什么 React 能把多个 setState 合并成一次渲染。


三、React 更新完整流程

整个更新链路可简化为 四个阶段

  1. 触发更新

    • 调用 setState,生成 update,挂到 fiber 的 updateQueue
    • 根据 lane(优先级)标记更新紧急程度
  2. 调度(Scheduler)

    • 根据优先级决定何时渲染
    • 高优先级立即执行,低优先级可能延迟
  3. render 阶段

    • 从根 fiber 构建新的 fiber 树(workInProgress)
    • 执行 processUpdateQueue → 统一应用更新队列,计算新的 state
  4. commit 阶段

    • before mutation → getSnapshotBeforeUpdate
    • mutation → 应用 DOM 变更
    • layout → 执行 useLayoutEffect / componentDidMount

最终才更新 UI。


四、批量更新(Batched Updates)

例子:

ini 复制代码
setCount(c => c + 1);
setCount(c => c + 1);

流程:

  1. 两次 setState → 生成两个 update,挂到同一个 queue。

  2. render 阶段依次应用:

    • baseState = 0
    • update1 → 1
    • update2 → 2
  3. commit 阶段一次性更新 UI

👉 结果:渲染一次,state = 2。


五、React17:为什么 setTimeout/Promise 不是批量?

React17 的批量更新依赖于 合成事件系统

  • React 分发合成事件时,用 batchedUpdates 包裹回调 → 批量更新。
  • setTimeoutPromise.then 属于原生调度,React 无法感知,不会进入 batchedUpdates

所以在 React17 里:

scss 复制代码
setTimeout(() => {
  setCount(c => c + 1); // render 一次
  setCount(c => c + 1); // render 再一次
}, 0);

👉 会渲染两次。


六、React18:自动批量更新

React18 引入 Automatic Batching

  • 不管 React 事件、setTimeout、Promise、async/await...
  • 只要在同一个任务里触发的更新 → 自动批量合并。
ini 复制代码
setTimeout(() => {
  setCount(c => c + 1);
  setCount(c => c + 1);
}, 0);

👉 React18 里只渲染一次,最终 state = 2。

需要立即更新时,可以用 flushSync

javascript 复制代码
import { flushSync } from 'react-dom';

flushSync(() => {
  setCount(c => c + 1); // 立即更新
});

七、isBatchingUpdates = true 的时机

isBatchingUpdates 决定 React 是否开启批量更新:

  • true → setState 只入队,不立即渲染
  • false → setState 立即触发渲染

React17

  • 合成事件回调、生命周期 → true
  • 原生事件 / setTimeout / Promise → false

React18

  • 自动批量更新 → 所有场景默认 true
  • 除非 flushSync 强制同步

源码简化版:

ini 复制代码
function batchedUpdates(fn, ...args) {
  const prev = isBatchingUpdates;
  isBatchingUpdates = true;
  try {
    fn(...args);
  } finally {
    isBatchingUpdates = prev;
    if (!isBatchingUpdates) flushUpdates();
  }
}

✅ 总结

  1. React 更新由 Update + UpdateQueue 驱动。
  2. render 阶段统一计算 state,commit 阶段更新 DOM。
  3. 批量更新合并多个 setState,只渲染一次。
  4. React17:只有合成事件是批量的,异步回调不是。
  5. React18:自动批量更新,几乎所有场景都合并。
  6. isBatchingUpdates 是批量开关,18 里几乎全局开启。

一句话概括:

React 更新就是 收集更新 → 按优先级调度 → render 阶段合并计算 → commit 阶段一次性更新

React18 之后,批量更新从「合成事件级」升级为「全局级」。


相关推荐
tanxiaomi3 小时前
通过HTML演示JVM的垃圾回收-新生代与老年代
前端·jvm·html
palpitation973 小时前
Android App Links 配置
前端
FuckPatience3 小时前
Vue 组件定义模板,集合v-for生成界面
前端·javascript·vue.js
sophie旭3 小时前
一道面试题,开始性能优化之旅(3)-- DNS查询+TCP(三)
前端·面试·性能优化
开心不就得了4 小时前
构建工具webpack
前端·webpack·rust
gerrgwg4 小时前
Flutter中实现Hero Page Route效果
前端
不枯石4 小时前
Matlab通过GUI实现点云的ICP配准
linux·前端·图像处理·计算机视觉·matlab
hhzz4 小时前
Pythoner 的Flask项目实践-在web页面实现矢量数据转换工具集功能(附源码)
前端·python·flask
lypzcgf4 小时前
Coze源码分析-资源库-编辑工作流-前端源码-核心流程/API/总结
前端·工作流·coze·coze源码分析·智能体平台·ai应用平台·agent平台