React 的完整渲染流程是一个精心设计的协调过程,涉及 react
和 react-reconciler
两个核心包的紧密协作。让我们深入解析整个渲染流程:
整体架构分层
php
┌──────────────────────┐
│ react-dom │ ← 平台特定渲染器
├──────────────────────┤
│ react-reconciler │ ← 协调器核心(Fiber架构)
├──────────────────────┤
│ react │ ← 公共API层(ReactElement/Hooks)
└──────────────────────┘
完整渲染流程解析
1. 初始化阶段(react 包)
javascript
// 用户代码
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(<App />);
createRoot()
创建根节点,初始化渲染器render()
触发首次渲染
2. 创建 Fiber 根节点(react-reconciler)
javascript
// ReactDOMRoot.js
function createRoot(container) {
return new ReactDOMRoot(container);
}
class ReactDOMRoot {
constructor(container) {
this._internalRoot = createFiberRoot(container);
}
render(element) {
updateContainer(element, this._internalRoot);
}
}
3. 协调过程(核心)
3.1 创建更新对象
javascript
// ReactFiberReconciler.js
function updateContainer(element, container) {
const update = createUpdate();
update.payload = { element };
enqueueUpdate(container.current, update);
scheduleUpdateOnFiber(container.current);
}
3.2 调度开始(ReactFiberWorkLoop.js)
javascript
function scheduleUpdateOnFiber(fiber) {
// 标记更新优先级
const lane = requestUpdateLane(fiber);
// 创建更新任务
const root = markUpdateLaneFromFiberToRoot(fiber, lane);
// 调度任务
ensureRootIsScheduled(root);
}
4. 渲染阶段(Render Phase)
4.1 工作循环(workLoop)
javascript
// ReactFiberWorkLoop.js
function workLoop(hasTimeRemaining, initialTime) {
while (workInProgress !== null && hasTimeRemaining) {
workInProgress = performUnitOfWork(workInProgress);
}
}
4.2 处理 Fiber 节点(beginWork)
javascript
// ReactFiberBeginWork.js
function beginWork(current, workInProgress, renderLanes) {
switch (workInProgress.tag) {
case FunctionComponent:
return updateFunctionComponent(
current, workInProgress, Component, resolvedProps, renderLanes
);
case ClassComponent:
return updateClassComponent(
current, workInProgress, Component, resolvedProps, renderLanes
);
case HostComponent:
return updateHostComponent(current, workInProgress, renderLanes);
// ...其他组件类型
}
}
4.3 函数组件处理
javascript
function updateFunctionComponent(current, workInProgress, Component, props) {
// 设置当前调度器
ReactCurrentDispatcher.current = HooksDispatcherOnMount;
// 执行函数组件
const nextChildren = renderWithHooks(
current, workInProgress, Component, props
);
// 协调子节点
reconcileChildren(current, workInProgress, nextChildren);
return workInProgress.child;
}
4.4 Hooks 处理(ReactFiberHooks.js)
javascript
function renderWithHooks(current, workInProgress, Component, props) {
// 初始化 hooks 状态
currentlyRenderingFiber = workInProgress;
workInProgress.memoizedState = null;
// 执行组件函数
const children = Component(props);
// 处理 effect 钩子
finishHooks(Component, props, children);
return children;
}
5. 提交阶段(Commit Phase)
5.1 提交前准备
javascript
function commitRoot(root) {
// 获取副作用链表
const finishedWork = root.finishedWork;
const effectTag = finishedWork.effectTag;
// 处理快照生命周期
commitBeforeMutationEffects();
// DOM 变更阶段
commitMutationEffects(root);
// 布局阶段
commitLayoutEffects(root);
}
5.2 DOM 变更(ReactFiberCommitWork.js)
javascript
function commitMutationEffects(root) {
while (nextEffect !== null) {
const effectTag = nextEffect.effectTag;
if (effectTag & Placement) {
commitPlacement(nextEffect);
}
if (effectTag & Update) {
commitWork(nextEffect);
}
if (effectTag & Deletion) {
commitDeletion(nextEffect);
}
nextEffect = nextEffect.nextEffect;
}
}
5.3 生命周期和布局效果
javascript
function commitLayoutEffects(root) {
while (nextEffect !== null) {
if (effectTag & Update) {
// 类组件的 componentDidMount/Update
if (tag === ClassComponent) {
instance.componentDidMount();
}
// 函数组件的 layout effects
commitHookEffectListMount(HookLayout | HookHasEffect);
}
nextEffect = nextEffect.nextEffect;
}
}
6. Fiber 架构核心概念
双缓存树结构:
javascript
class FiberNode {
constructor(tag, pendingProps, key) {
// 节点类型
this.tag = tag;
// 状态相关
this.memoizedState = null; // Hooks 链表
this.updateQueue = null; // 更新队列
// 树结构
this.return = null; // 父节点
this.child = null; // 第一个子节点
this.sibling = null; // 兄弟节点
// 双缓存
this.alternate = null; // 指向另一棵树上的对应节点
// 副作用
this.effectTag = NoEffect;
this.nextEffect = null;
}
}
7. 更新流程(setState)
- 用户调用
setState()
- 创建更新对象并入队
- 调度更新任务
- 触发新的渲染阶段
- 生成新的 Fiber 树
- 与当前树进行 Diff
- 收集变更到副作用链表
- 提交变更到 DOM
8. Diff 算法核心(reconcileChildren)
javascript
function reconcileChildren(current, workInProgress, nextChildren) {
if (current === null) {
// 首次渲染
workInProgress.child = mountChildFibers(
workInProgress, null, nextChildren
);
} else {
// 更新
workInProgress.child = reconcileChildFibers(
workInProgress, current.child, nextChildren
);
}
}
Diff 策略:
- 相同类型节点复用
- 列表使用 key 优化
- 仅同级比较
- 优先检测常见操作(尾部添加/删除)
9. 性能优化机制
- 时间切片(Time Slicing):将渲染工作分成小块
- 任务优先级(Lane模型):区分不同优先级更新
- 自动批处理:合并多次状态更新
- Suspense:非阻塞渲染
- Offscreen:隐藏组件保持状态
调试建议
-
启用 React DevTools 的 "Highlight updates"
-
在关键函数添加断点:
performUnitOfWork
beginWork
completeUnitOfWork
commitRoot
-
使用 React 的
__DEBUG
标志:bashyarn build react/index,react-dom/index,react-reconciler --debug
理解 React 渲染流程的关键在于掌握 Fiber 架构的双缓存机制和渲染/提交两阶段分离的设计理念。这种架构使 React 能够实现增量渲染、任务中断恢复等高级特性,为现代 Web 应用提供了强大的性能基础。