2024年4月15日

React渲染流程

React渲染流程全链路分析:从createRoot到render

1. 初始化阶段 - createRoot

入口文件

export * as ReactDom from "../packages/react-dom/client.ts";
export{ Fragment, Component } from "../packages/react";
function MyFunctionComponent() {
  return <div>MyFunctionComponent</div>;
}
class MyComponent extends Component {
  render() {
    return <div>MyComponent
      <MyFunctionComponent />
      <h2>123</h2>
    </div>;
  }
}

createRoot方法实现

export const createRoot = (container: Container): RootType => {
  // 创建一个根节点
  const root: FiberRoot = createFiberRoot(container);
  return new ReactDomRoot(root); 
};

FiberRoot创建过程

export function createFiberRoot(containerInfo: Container): FiberRoot {
  const root: FiberRoot = new FiberRootNode(containerInfo);
  const uninitializedFiber: Fiber = createFiber(HostRoot, null, null);
  root.current = uninitializedFiber;
  uninitializedFiber.stateNode = root;
  return root;
}

核心流程:

  1. 用户调用ReactDom.createRoot(document.getElementById("root4")!)
  2. 创建FiberRootNode实例,保存DOM容器信息
  3. 创建HostRoot类型的Fiber节点作为根Fiber
  4. 建立FiberRoot和RootFiber的相互引用关系
  5. 返回ReactDomRoot实例,包含render方法

2. 渲染阶段 - render

render方法实现

render(children: ReactNodeList) {
  updateContainer(children, this._internalRoot);
}

updateContainer实现

export function updateContainer(element: ReactNodeList, container: FiberRoot) {
  const current = container.current!;
  current.memoizedState = {element};
  scheduleUpdateOnFiber(container, current);
}

调度更新

export function scheduleUpdateOnFiber(root: FiberRoot, current: Fiber) {
  // 设置当前正在处理的FiberRoot(整个应用的根容器)
  workInProgressRoot = root;
  // 设置当前正在处理的Fiber节点(从current开始协调)
  workInProgress = current;
  // 启动调度流程(最终会触发performConcurrentWorkOnRoot)
  ensureRootIsScheduled(root);
}

3. 协调阶段 - Reconciliation

执行根节点工作

export function performConcurrentWorkOnRoot(root: FiberRoot) {
  // ! 阶段1:Render阶段(可中断的协调过程)
  // 同步渲染Fiber树(在简化版中暂时使用同步模式)
  renderRootSync(root);
  console.log("Fiber树构建完成:", root);
  // ! 阶段2:Commit阶段(不可中断的DOM更新)
  // 获取已完成的workInProgress树(即current.alternate)
  const finishedWork: Fiber = root.current?.alternate!;
  // 将完成的Fiber树挂载到root.finishedWork
  root.finishedWork = finishedWork;
  // 执行commit流程(DOM更新、生命周期调用等)
  commitRoot(root);
}

构建Fiber树

function renderRootSync(root: FiberRoot) {
  // ! 1.render开始 - 保存当前执行上下文并设置RenderContext标志
  const prevExecutionContext = executionContext;
  executionContext |= RenderContext;
  
  // !2. 初始化 - 准备新的工作栈,创建workInProgress树
  prepareFreshStack(root);
  
  // !3. 遍历构建Fiber树 - 同步模式下循环处理所有工作单元
  workLoopSync();
  
  // !4. render结束 - 恢复之前的执行上下文状态
  executionContext = prevExecutionContext; // 恢复之前的值
  workInProgressRoot = null; // 整个流程结束,重置workInProgressRoot
}

工作循环

function workLoopSync() {
  while (workInProgress !== null) {
    performUnitOfWork(workInProgress);
  }
}

处理单个工作单元

function performUnitOfWork(unitWork: Fiber) {
  // 获取当前Fiber对应的current树节点(即上次渲染的版本)
  const current = unitWork.alternate;
  
  // ! 阶段1:beginWork处理
  let next = beginWork(current, unitWork);
  
  // 根据beginWork结果决定后续流程
  if (next === null) {
    // ! 情况1:没有产生新的工作单元(到达叶子节点)
    completeUnitOfWork(unitWork);
  } else {
    // ! 情况2:存在子节点需要处理
    workInProgress = next;
  }
}

4. 提交阶段 - Commit

提交根节点

function commitRoot(root: FiberRoot) {
  // ! 1.commit 开始 - 保存当前执行上下文并设置CommitContext标志
  const prevExecutionContext = executionContext;
  executionContext |= CommitContext;
  // ! 2. commit阶段 - mutation阶段更新DOM树
  commitMutationEffects(root, root.finishedWork!);
  // ! 3. commit结束 - 恢复之前的执行上下文状态
  executionContext = prevExecutionContext; // 恢复之前的值
  workInProgressRoot = null; // 整个流程结束,重置 workInProgressRoot
}

5. 完整调用链路

  1. 入口调用

    ReactDom.createRoot(document.getElementById("root4")!).render(<div><MyComponent /></div>);
  2. 创建阶段

    • createRootcreateFiberRootnew FiberRootNodecreateFiber(HostRoot)
    • 返回 ReactDomRoot 实例
  3. 渲染阶段

    • renderupdateContainerscheduleUpdateOnFiberensureRootIsScheduled
    • 调度执行 performConcurrentWorkOnRoot
  4. 协调阶段

    • renderRootSyncprepareFreshStackworkLoopSync
    • 循环执行 performUnitOfWorkbeginWork/completeWork
    • 处理组件:MyComponent类组件调用render方法,MyFunctionComponent函数组件直接执行
  5. 提交阶段

    • commitRootcommitMutationEffects
    • DOM操作:创建、更新、删除DOM节点
    • 内容渲染到浏览器

6. 关键数据结构

  1. FiberRoot:整个应用的根节点,包含:

    • current: 指向当前Fiber树
    • containerInfo: DOM容器
    • finishedWork: 完成工作的Fiber树
  2. Fiber:React元素对应的工作单元,包含:

    • tag: 组件类型(如ClassComponent、FunctionComponent)
    • type: 元素类型
    • stateNode: DOM节点或组件实例
    • return/child/sibling: 父/子/兄弟Fiber节点
    • memoizedState: 上次渲染的状态
    • flags: 副作用标记

7. 渲染示例分析

以示例代码中的组件渲染为例:

ReactDom.createRoot(document.getElementById("root4")!).render(<div>
  <MyComponent />
</div>);
  1. 创建FiberRoot和HostRoot Fiber
  2. 调用render方法,传入JSX
  3. 更新容器,调度更新
  4. 构建Fiber树:
    • div → HostComponent
    • MyComponent → ClassComponent → 调用render方法
    • MyFunctionComponent → FunctionComponent → 直接执行函数
  5. 完成Fiber树构建
  6. 提交变更到DOM
  7. 浏览器渲染页面,显示组件内容

这就是React从createRoot到render完成内容渲染到浏览器的完整流程。

Share