React 源码架构解析
约 1448 字大约 5 分钟
布欧-Lewyon
2026-05-15
首页 › React › 源码与架构 › React 源码架构解析
理解 React 源码架构,有助于写出高性能的组件、定位疑难 Bug,也能更从容地面试底层原理。
总体架构
React 16+(Fiber 架构)分为三层:
| 层 | 位置 | 职责 |
|---|---|---|
| Scheduler(调度器) | react/packages/scheduler | 任务优先级调度,时间切片 |
| Reconciler(协调器) | react/packages/react-reconciler | 构建 Fiber 树、Diff、副作用收集 |
| Renderer(渲染器) | react-dom / react-native | 将虚拟 DOM 变更应用到宿主环境 |
核心数据结构:Fiber
Fiber 是 React 16 引入的数据结构,取代了 Stack Reconciler 递归不可中断的模型。
// Fiber 节点简化定义
interface Fiber {
// 类型信息
tag: WorkTag; // 节点类型(FunctionComponent / ClassComponent / HostComponent 等)
type: any; // 组件自身(函数/类/原生标签字符串)
key: null | string; // key 属性
elementType: any; // 开发者写的类型
// 树结构
return: Fiber | null; // ⭐ 父节点
child: Fiber | null; // ⭐ 第一个子节点
sibling: Fiber | null; // ⭐ 下一个兄弟节点
index: number; // 在兄弟节点中的位置
// 双缓存
alternate: Fiber | null; // ⭐ 指向 current 树中对应的 Fiber
// 状态与 props
pendingProps: any; // 新的 props
memoizedProps: any; // 上一次渲染的 props
memoizedState: any; // 上一次渲染的 state(对于函数组件:Hooks 链表)
updateQueue: any; // 状态更新队列
// 副作用
flags: Flags; // 标记(Placement / Update / Deletion 等)
subtreeFlags: Flags; // 子树副作用汇总
deletions: Fiber[] | null; // 待删除的子节点
// 优先级
lanes: Lanes; // 本节点的更新优先级
childLanes: Lanes; // 子节点的更新优先级
// 当前调度的额外数据
_debugSource: Source | null; // 源码位置(开发环境)
}关键设计思想
- Fiber 以链表代替了递归:
return → child → sibling构成一棵链表树 - 每个 Fiber 节点就是一个"工作单元":执行一个 Fiber 后,检查是否有剩余时间,无则让出主线程
- alternate 指针:指向上一次渲染的 Fiber 节点,复用已有的 DOM 实例
双缓存机制
React 在内存中维护两棵 Fiber 树:
- current:当前屏幕上显示内容对应的 Fiber 树
- workInProgress(wip):正在构建中的 Fiber 树
工作流程:
- 首次渲染:创建
current树 - 触发更新:在
wip树上进行 Diff + 副作用标记 - 提交(commit):
wip树变为新的current树 - 下一次更新:复用之前的
current树作为新的wip树
双缓存的优势:复用已有 Fiber 节点(DOM 实例不销毁),避免重复创建。
三阶段工作流程
一次更新分为三大阶段:
1. Render 阶段(可中断)
调用 performUnitOfWork 遍历 Fiber 树,为每个节点:
function performUnitOfWork(unitOfWork: Fiber): Fiber | null {
// 1. 处理当前节点:Diff props,返回第一个子节点
const next = beginWork(unitOfWork);
// 处理 memoizedProps 等
if (next) return next; // 有子节点 → 继续深入
// 2. 没有子节点 → 完成当前节点
let completed = unitOfWork;
while (completed) {
completeUnitOfWork(completed);
// 有兄弟节点 → 转到兄弟
if (completed.sibling) return completed.sibling;
// 没有兄弟 → 回溯到父节点
completed = completed.return;
}
return null; // 整棵树遍历完毕
}2. Commit 阶段(不可中断)
分为三个子阶段:
| 阶段 | 执行内容 |
|---|---|
| before mutation | 处理 Snapshot flag(getSnapshotBeforeUpdate) |
| mutation | ⭐ 增/删/改 DOM、卸载 useEffect cleanup |
| layout | 执行 useLayoutEffect、设置 ref、回调 |
3. 微任务中的被动 Effects
useEffect 不阻塞主线程,在 commit 完成后以异步方式执行:
优先级与调度
Lane 模型
React 18 用 Lane(位掩码)替代了 React 17 的 expirationTime:
// lane 示例(共 31 位)
export const NoLanes = 0b0000000000000000000000000000000;
export const SyncLane = 0b0000000000000000000000000000001; // 同步(最高)
export const InputContinuousLane = 0b0000000000000000000000000000100;
export const DefaultLane = 0b0000000000000000000000000001000;
export const TransitionLane = 0b0000000000000000001000000000000;
export const IdleLane = 0b0100000000000000000000000000000; // 空闲优势:
- 位运算判断包含关系:
laneA & laneB !== 0 - 支持批量合并:
mergeLanes(a, b)用|操作 - 支持多优先级共存
Scheduler(调度器)
// 时间切片核心逻辑
function workLoop(deadline: IdleDeadline) {
let shouldYield = false;
while (nextUnitOfWork && !shouldYield) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
shouldYield = deadline.timeRemaining() < 1; // 还有时间吗?
}
// 如果时间用完,让出主线程,等下一次 requestIdleCallback
if (nextUnitOfWork) {
requestIdleCallback(workLoop);
} else {
commitRoot(); // 整棵树完成 → 提交
}
}整体流程汇总
小结
| 概念 | 一句话总结 |
|---|---|
| Fiber | 可中断的工作单元,链表结构串联组件树 |
| 双缓存 | current + workInProgress 两棵树,复用 DOM 实例 |
| Lane | 位掩码优先级系统,支持细粒度中断和合并 |
| Scheduler | 时间切片,每 5ms 检查是否让出主线程 |
| 三阶段 | Render(可中断)→ Commit(不可中断)→ Effects(异步) |
下一节:Diff 算法详解
