React 核心渲染流程

4 阅读6分钟

初始化渲染

  • 首次渲染是从无FIber树到构建Current树并渲染到页面的过程,流程如下
graph LR
A[调用ReactDOM.createRoot/渲染根组件]-->B[创建根Fiber节点]
B-->C[Scheduler标记高优先级任务]
C-->D[启动协调阶段 构建WorkInProgress树]
D-->E[遍历组件树创建Fiber节点]
E-->F[创建真实DOM节点]
F-->G[标记Placement副作用]
G-->H[WorkInProgress树构建完成]
H-->I[进入提交阶段]
I-->J[执行DOM插入操作]
J-->K[切换RootFiber指针]
K-->L[页面首次渲染完成]

1. 根节点初始化:

  • 调用ReactDom.createRoot(rootDom).render(<App/>)时,React先创建Fiber节点(RootFiber),作为整个Fiber树的入口
  • 根Fiber节点标记首次渲染标识,Scheduler为其分配最高优先级(无需等待,立即执行)

2. 协调阶段(构建WorkInProgress树)

  • react-reconciler从RootFiber开始,深度优先遍历组件树(基于Fiber链表的child/return/sibling指针)
  • 对每个组件
    • 函数组件:执行组件函数,解析JSX生成虚拟DOM,在创建对应的Fiber节点
    • 类组件:实例化组件(new ClassComponent()),调用render()方法生成虚拟DOM,创建Fiber节点
    • 原生标签(如div):调用ReactDOM的createInstance创建真是DOM节点,关联到Fiber节点的stateNode属性
  • 为所有Fiber节点标记Placement(插入)副作用(首次渲染所有节点都需要插入DOM)

3. 提交阶段(渲染到页面)

  • 遍历副作用链表,调用ReactDOM的appendChild将真实DOM节点插入到根容器
  • 执行组件生命周期/钩子:函数组件执行useEffect(无cleanup)、类组件执行componentDidMount
  • 切换RootFiber的current指针,将WorkInProgress树设为Current树,首次渲染完成

更新渲染(状态/props变化)

  • 更新渲染时React最核心的场景(如setState/useState触发),完整流程覆盖(更新触发-->调度-->协调-->提交)全链路,也是所有核心模块协作的核心体现
graph TD
    A[触发更新setStte/useState/Props变化] --> B[创建 Update 对象 加入Fiber节点的更新队列]
    B --> C[标记 Fiber节点为待更新 请求Scheduler调度]
    C --> D[Scheduler 分配优先级expirationTime 加入任务队列]
    D --> E[Scheduler 启动调度循环-检查切片高优先级任务]
    E -- 有执行时间 --> F[react-reconciler启动协调阶段 复用Current树构建 WorkInProgress 树]
    E -- 无执行时间 --> G[暂停任务 让出主线程 等待下一次调度]
    F --> H[计算组件最新状态 消费Update队列]
    H --> I[对比新旧Fiber节点 Diff算法]
    I --> J[标记差异对应的副作用 Placement Update Deletion]
    J --> K{是否有下一个Fiber节点?}
    K -- 是 --> E
    K -- 否 --> L[WorkInProgress 树构建完成]
    L --> M[react-reconciler进入提交阶段]
    M --> N[执行副作用 先删Deletion--> 再插 更 Placement Update]
    N --> O[执行生命周期钩子 useEffect清理+执行 componentDidUpdate]
    O --> P[切换 RootFiber指针 WorkInProgress --> Current]
    P --> Q[页面更新完成]
    G --> E

1. 更新触发与队列管理

  • 当调用setState(newState)或setCount(c=> c+1)时,React不会立即更新状态,而是创建Update对象(包含新状态、优先级、回调),加入该组件Fiber节点的更新队列(链表结构)
  • 若同一事件循环内多次调用setState,Update会批量接入队列(批量更新优化),避免多次渲染

2. 任务调度(Scheduler核心副作用)

  • Fiber节点标记待更新后,向Scheduler发起调度请求
  • Scheduler为任务分配过期时间(expiration Time)(优先级越高,过期时间越短),加入优先级队列
  • Scheduler启动调度循环
    • 先检查是否有过期任务(必须立即执行)
    • 再检查主线程空闲时间,分配时间切片(<=5ms)
    • 若有高优先级任务(如用户输入),中断当前低优先级任务,优先执行高优先级任务

3. 协调阶段(react-reconciler + Fiber核心)

  • react-reconciler拿到执行权限后,从RootFiber开始,基于Current树复用已有Fiber节点创建的WorkInProgress树(避免重复创建节点)
  • 消费更新队列:遍历组件的Update链表,计算组件最新状态(如类组件合并setState的多个Update,函数组件并执行useState的更新函数)
  • Diff算法执行
    • 同层级对比:值对比同一层级的Fiber节点,跨层级直接标记删除 + 插入
    • 组件类型对比:类型不同则销毁就Fiber树,类型相同则对比Props
    • 列表对比:通过Key匹配节点,用最长递增子序列最小化DOM移动
  • 标记副作用:为有差异的节点标记effectTag(如Update:更新属性、Deletion:删除节点),并将所有副作用节点串联成副作用链表(提升提交阶段效率)

4. 提交阶段(不可中断,保证DOM一致性)

  • 副作用执行:按先删后插的顺序遍历副作用链表,避免DOM布局偏移
    • Deletion:删除不需要的DOM节点,执行类组件componentWillUnmount、函数组件useEffect的清理函数
    • Placement/Update:插入新DOM节点、更新已有节点的属性(如className、事件监听)
  • 生命周期/执行钩子:类组件执行componentDidUpdate,函数组件执行useEffect(先执行上一轮的cleanup,再执行本轮的回调)
  • 切换Fiber树:将RootFiber的Current指针指向WorkInProgress树,完成双缓存的切换,更新流程结束

React18+新增:并发渲染(Concurrent Rendering)

React18 基于上述核心流程,新增并发渲染能力,核心是让协调阶段支持暂停/恢复/放弃,主要体现在:

1. 优先级调度强化: 通过startTransition/useDeferredValue标记低优先级更新,Scheduler会优先处理高优先级任务(如输入),低优先级任务可被中断

2.Suspense支持: 渲染懒加载组件时,react-reconciler会暂停协调阶段,直到组件加载完成,再恢复渲染(fallback内容临时展示)

3.自动批处理: 无论更新新触发位置(如setTimeout/事件回调),都默认批量处理Update,减少渲染次数

核心总结

1. 两大阶段

  • 协调阶段(可中断,计算差异标记副作用) + 提交阶段(不可中断,执行DOM操作)

2. 双缓存树:

  • Current树对应真实的DOM,WorkInProgress树计算差异,切换指针完成更新

多模块协作

3.1 依赖底层:Fiber架构是基础载体

  • Fiber节点是最小任务单元:每个Fiber节点对应一个组件/原生节点,存储了节点类型、Props、优先级、副作用、遍历指针(return/child/sibling)等核心信息
  • Fiber树是状态容器:维护Current(当前渲染树)和WorkInProgress(构建中树)双缓存结构,是react-reconciler执行Diff的基础
  • 对其他模块的支撑
    • 给Scheduler:提供任务中断点--Fiber链表结构可保存遍历状态,让Scheduler能暂停/恢复任务
    • 给react-reconciler:提供遍历对象--react-reconciler遍历Fiber树完成Diff和副作用标记

3.2 调度核心:Scheduler调度器是大脑、任务管理者

  • Scheduler不直接处理渲染逻辑,只负责任务的调度规则,依赖Fiber的优先级信息,为react-reconciler提供执行时机
  • 依赖Fiber:读取Fiber节点的expirationTime(过期时间)确定任务优先级,决定是否中断当前react-reconciler
  • 支撑react-reconciler
    • 为react-reconciler的协调任务分配时间切片(<=5ms),避免阻塞主线程
    • 当高优先级任务(如用户输入)到来时,中断当前低优先级的协调任务,让react-reconciler先处理高优先级任务

3.3 执行核心:react-reconciler协调层是业务执行者

  • 负责具体执行什么任务(基于Fiber节点执行Diff算法、标记副作用、驱动平台更新)
  • react-reconciler是连接Scheduler、Fiber和具体渲染平台的桥梁,同时依赖前两者
  • 依赖Scheduler:遵循Scheduler的调度指令--只在Scheduler分配的时间片内执行协调任务,收到中断信号时立即暂停
  • 依赖Fiber:遍历Fiber树执行Diff算大,标记副作用(effectTag),并将副作用链表传递给平台层
  • 对外输出:将协调结果(副作用)转化为平台特定操作(如DOM插入/更新),实现跨平台渲染
  • 更新队列、合成事件系统、Render等模块补充触发更新和平台落地能力