FumadocsZDecode
React

React 渲染流程

从 JSX 写到屏幕上显示,React 经过编译 → 协调 → 提交三个大阶段。理解这条链路是面试高频考点,也能帮你定位性能问题。

JSX
 ↓ Babel 编译
React.createElement()
 ↓ 返回 JS 对象
Virtual DOM(React Element)
 ↓ Fiber 架构
Fiber Tree
 ↓ Render 阶段(Diff)
Effect List
 ↓ Commit 阶段(不可中断)
真实 DOM 更新

浏览器渲染页面

一、JSX → Virtual DOM

JSX 不是合法的 JS,浏览器不认识它。Babel 先把 JSX 解析成 AST(抽象语法树),再编译为函数调用:

// 你写的 JSX
const el = <div className="box">hello</div>

// Babel 编译后(React 17 前)
const el = React.createElement('div', { className: 'box' }, 'hello')

// React 17+ 自动导入
const el = jsx('div', { className: 'box', children: 'hello' })

createElement 返回的不是 DOM,而是一个普通的 JS 对象——这就是 Virtual DOM(也叫 React Element):

export default {
  type: 'div',
  props: { className: 'box', children: 'hello' },
}

React 用这个 JS 对象描述"页面应该长什么样",而不是直接操作昂贵的真实 DOM。


二、Virtual DOM → Fiber Tree

React 不会直接 diff Virtual DOM,而是先把它转换成 Fiber Tree——每个组件/元素对应一个 Fiber 节点:

// Fiber 节点核心字段
{
  type,        // 组件类型
  stateNode,   // 对应的真实 DOM
  child,       // 第一个子节点
  sibling,     // 下一个兄弟节点
  return,      // 父节点
  flags,       // 标记(Placement / Update / Deletion)
}

Fiber 解决的核心问题:React 16 之前使用递归 diff,无法中断,大页面会卡顿。Fiber 把渲染任务拆成小单元,变成可中断的链表遍历,支持暂停、恢复和优先级调度。


三、Render 阶段(Diff)

Render 阶段的核心任务:对比新旧 Fiber Tree,找出变化。这个阶段可以中断,React 会按优先级分片执行。

Diff 三条规则

React 的 Diff 算法遵循以下三条规则:

规则判断条件React 行为
节点类型不同divp销毁旧节点,创建新节点
节点类型相同div.adiv.b复用 DOM,只更新属性
列表靠 key 识别key 相同复用节点;无 key 则暴力按序 diff

React Diff 是同层比较,不会跨层级。复杂度从 O(n³) 降到 O(n)。

Diff 完成后,React 把需要变更的节点记录为 Effect List(Placement / Update / Deletion),交给下一阶段。


四、Commit 阶段

Commit 阶段不可中断,React 在此阶段真正操作真实 DOM:

  1. 创建 DOMdocument.createElement()
  2. 更新属性dom.className = 'box'
  3. 插入节点parent.appendChild()
  4. 删除节点removeChild()
  5. 执行副作用useEffectcomponentDidMountcomponentDidUpdate 等生命周期

DOM 更新完成后,浏览器执行 style → layout → paint → composite 的渲染管线,最终显示页面。


五、一次 setState 发生了什么

这是面试高频题。调用 setCount(count + 1) 后:

1. 创建更新对象 { action: count + 1 }
2. 放入更新队列(UpdateQueue)
3. Scheduler 调度(决定同步/过渡/低优先级)
4. 函数组件重新执行 → 生成新 Virtual DOM
5. Diff 新旧 Fiber Tree → 生成 Effect List
6. Commit → 更新真实 DOM

多个 setState 会被 React 合并在同一批次处理,减少重复渲染。


六、React 为什么快

React 的快不是因为 Virtual DOM 本身,而是这几个机制叠加的结果:

  • 批量更新 — 合并多个 setState,减少 DOM 操作次数。
  • Diff 优化 — 同层比较 + key,将复杂度降到 O(n)。
  • Fiber 可中断 — 避免长时间阻塞主线程,保持页面响应。
  • 增量更新 — 只更新变化的部分,不全量重绘。

七、 一句话总结

JSX 经 Babel 编译为 React.createElement 调用,生成 Virtual DOM(JS 对象)。React 把它转成 Fiber Tree,在 Render 阶段通过同层 Diff 找出变化,记录为 Effect List;在 Commit 阶段一次性操作真实 DOM,由浏览器完成渲染。Fiber 架构让这个过程可中断、可调度。

On this page