React中Fiber树构建过程详解——react中render一个App组件(包含子组件)的流程详解

在 React 中,渲染一个包含子组件的组件涉及一系列底层流程,包括构建虚拟 DOM(React Element)、协调(Reconciliation)、Fiber 树管理和最终的 DOM 操作。以下是一个从底层解析的详细流程:


1. 初始化阶段

当开发者调用 React 的顶层 API 渲染组件时,例如:

jsx 复制代码
ReactDOM.createRoot(document.getElementById('root')).render(<Parent />);

React 开始构建组件树。假设 Parent 组件包含子组件:

jsx 复制代码
function Parent() {
  return (
    <div>
      <Child />
    </div>
  );
}

function Child() {
  return <p>Hello, World!</p>;
}

2. 创建 React Element

当调用 <Parent /> 时,React 会将其转化为React 元素树(虚拟 DOM 树)。这一步是通过调用组件函数实现的:

  • React 会调用 Parent,执行其返回值。

  • Parent 返回的是一个 JSX 树,它被转化为一个 JavaScript 对象,称为 React Element

    javascript 复制代码
    const parentElement = {
      type: 'div',
      props: {
        children: {
          type: Child, // 子组件
          props: {}, // 子组件的 props
        },
      },
    };
  • 对于 Child,React 会继续递归调用它,得到:

    javascript 复制代码
    const childElement = {
      type: 'p',
      props: {
        children: 'Hello, World!',
      },
    };

3. 进入协调(Reconciliation)阶段

React 开始协调组件树,即比较新旧虚拟 DOM,决定需要的更新。

构建 Fiber 节点

React 为每个 React Element 创建一个对应的 Fiber 节点。Fiber 是 React 的内部数据结构,用于描述组件树的状态:

  • 父组件 Parent Fiber:

    javascript 复制代码
    const parentFiber = {
      tag: 'HostComponent', // 表示是原生 DOM 元素
      type: 'div', // 节点类型
      stateNode: null, // 对应的真实 DOM(稍后会赋值)
      child: childFiber, // 指向子组件的 Fiber
      sibling: null, // 指向兄弟节点
    };
  • 子组件 Child Fiber:

    javascript 复制代码
    const childFiber = {
      tag: 'HostComponent', // 原生 DOM 元素
      type: 'p', // 节点类型
      stateNode: null, // 对应的真实 DOM
      child: null, // 没有子节点
      sibling: null, // 没有兄弟节点
    };
协调子节点

React 调用 reconcileChildren 比较新旧 Fiber 树的差异,决定是否复用、删除或新增节点。

  • 在首次渲染时,旧 Fiber 树为空,React 会根据 React 元素树直接构建 Fiber 树。
  • 对于每个 Fiber 节点,React 会递归地调用 beginWorkcompleteWork,处理子组件并更新其状态。

4. 渲染阶段(Render Phase)

beginWork 函数

beginWork 是 Fiber 协调的核心函数。它处理当前 Fiber 节点,并根据组件类型执行不同逻辑:

  • 对于 Parent<div>):

    • 检查是否需要更新:首次渲染会直接创建。
    • 调用 reconcileChildren 处理子节点,递归进入 Child 节点。
  • 对于 Child<p>):

    • 继续调用 reconcileChildren,但因为它是文本节点,直接处理为完成状态。
创建 DOM 节点

当 Fiber 节点处理完毕后,React 会通过 completeWork 创建真实的 DOM 节点,并赋值给 stateNode

  • 对于 Parent

    javascript 复制代码
    parentFiber.stateNode = document.createElement('div');
  • 对于 Child

    javascript 复制代码
    childFiber.stateNode = document.createElement('p');
    childFiber.stateNode.textContent = 'Hello, World!';

5. 提交阶段(Commit Phase)

提交阶段是 Fiber 树计算完成后,将更新应用到真实 DOM 的过程。

执行 DOM 操作

React 将根据 Fiber 树生成的 stateNode,完成以下 DOM 操作:

  • ParentstateNode<div>)挂载到根 DOM 容器。
  • ChildstateNode<p>)作为子节点,插入到 ParentstateNode 中。
生命周期回调

对于有生命周期方法(如类组件)的组件,会在此阶段触发 componentDidMountuseEffect 回调。


6. 最终 DOM 输出

最终,React 在真实 DOM 中渲染出:

html 复制代码
<div>
  <p>Hello, World!</p>
</div>

7. 优化机制

React 的底层设计支持高效渲染:

  • Fiber 数据结构:实现任务切片、可中断更新。
  • key 属性 :通过 key 帮助 React 精确复用子节点,减少无意义的 DOM 操作。
  • 批量更新:React 会在批量更新模式下合并多次更新,减少重绘。

8. 总结

  1. React 将 JSX 转化为 React 元素树。
  2. React 构建 Fiber 树,递归调用组件以处理子组件。
  3. 在协调阶段,React 比较新旧 Fiber 树,生成新的 Fiber 树。
  4. 在渲染阶段,React 创建真实 DOM 并在提交阶段更新 DOM。
  5. 通过优化机制(如任务切片、批量更新、key 比较等)提升性能。

React 的设计通过 Fiber 架构实现了高效渲染和可中断任务调度,使得复杂组件树的渲染和更新性能得到极大提升。

在 React 中,Fiber 架构通过 双缓存机制(Double Buffering) 实现了高效的更新和渲染。双缓存是 React Fiber 系统的核心设计之一,它使得 React 可以在后台异步构建新 Fiber 树,同时保持当前界面的稳定性。

以下是详细的解析和 Fiber 树的构建过程。


一、双缓存机制的简介

1. 双缓存的核心思想

React 使用两棵 Fiber 树:

  • current Fiber 树:当前屏幕上显示的 Fiber 树,表示已渲染到 DOM 的 UI 状态。
  • workInProgress Fiber 树 :新的一棵 Fiber 树,用于处理更新。当更新完成后,这棵树会替代 current 成为新的 current

这两棵树通过 alternate 属性互相连接:

javascript 复制代码
workInProgress.alternate === current; // 双向连接
current.alternate === workInProgress;

2. 双缓存的优点

  • 异步更新 :React 可以在后台安全地构建 workInProgress,不影响当前界面。
  • 性能优化 :仅在 workInProgress 完成后切换为 current,最大限度减少渲染期间的 DOM 操作。
  • 错误恢复 :在更新失败时,可以直接回退到 current 树,不影响用户体验。

二、Fiber 树的结构

每个 Fiber 节点代表一个 React 元素(如组件、DOM 节点、文本节点等),其结构如下:

javascript 复制代码
const fiberNode = {
  type,            // 节点类型,例如 'div' 或组件函数
  tag,             // 节点标签,表示是 DOM 节点、函数组件还是类组件
  key,             // 用于列表比较的唯一标识
  stateNode,       // 真实 DOM 节点或类组件实例
  child,           // 第一个子 Fiber 节点
  sibling,         // 下一个兄弟 Fiber 节点
  return,          // 父 Fiber 节点
  alternate,       // 指向当前树中的对应 Fiber 节点
  effectTag,       // 表示需要对节点执行的操作类型(如插入、删除、更新)
  updateQueue,     // 存储该节点的更新队列
};

三、Fiber 树的构建过程

1. 初始化阶段

当 React 首次渲染时,React 会根据 React.createElement 的返回值生成初始 Fiber 树(即 current 树)。

步骤:
  1. 创建根 Fiber 节点 :React 为 ReactDOM.createRoot 创建一个 rootFiber,作为根节点。

    javascript 复制代码
    const rootFiber = {
      tag: 'HostRoot', // 根 Fiber 的标签
      stateNode: container, // 指向挂载的 DOM 容器
      child: null, // 根 Fiber 的子节点
    };
  2. 递归生成 Fiber 树

    • 对根组件调用 beginWork
    • 根据返回的 React 元素,递归生成子 Fiber 节点并连接父子关系。

2. 更新阶段(使用双缓存)

当组件状态或属性发生变化时,React 会在 workInProgress 树上进行更新操作。

步骤解析:
(1) 创建 workInProgress
  • React 会复用 current 树中的大部分 Fiber 节点,通过 alternate 连接生成 workInProgress 树:

    javascript 复制代码
    const workInProgress = current.alternate || createNewFiber(current);
  • 如果存在 current.alternate,表示已存在 workInProgress,React 会复用它;否则,创建一个新的 Fiber 节点。

(2) 调用 beginWork 构建 Fiber 树

React 的协调逻辑从根节点开始,递归调用 beginWork 构建或更新每个 Fiber 节点。

beginWork 的核心任务:

  1. 检查更新类型:

    • 如果节点没有变化,复用 current
    • 如果有变化,创建新的 Fiber 节点。
  2. 调用子组件或函数组件的 render 方法,生成新的子 React 元素。

  3. 调用 reconcileChildren 比较子节点,生成或复用子 Fiber 节点,并连接到当前 Fiber 节点。

示例:

对于以下 JSX:

jsx 复制代码
function App() {
  return (
    <div>
      <p>Hello, World!</p>
    </div>
  );
}

beginWork 的流程:

  • <div> 节点创建 Fiber。
  • 调用 reconcileChildren 处理子节点 <p>
  • <p> 节点创建或复用 Fiber。
(3) 完成 completeWork 阶段

当 Fiber 树的所有节点完成构建后,React 进入 completeWork 阶段:

  1. 为每个 Fiber 节点生成对应的真实 DOM 节点(如果是原生节点)。
  2. 将子节点的 DOM 节点挂载到父节点的 stateNode 上。

3. 提交阶段

workInProgress 树构建完成后,React 会进入提交阶段(Commit Phase):

切换 Fiber 树
  • workInProgress 树设置为新的 current 树:

    javascript 复制代码
    root.current = workInProgress;
执行 DOM 操作
  • 根据 Fiber 节点的 effectTag,执行插入、删除或更新 DOM 的操作。

四、Fiber 树构建的性能优化

  1. 优先级调度

    • React 根据任务优先级(如用户交互任务 vs 数据更新任务)灵活地分片处理 Fiber 节点。
    • 高优先级任务(如用户输入)可打断低优先级任务。
  2. 复用机制

    • Fiber 节点通过 alternate 实现复用,避免重复创建。
    • 对于未变更的节点,直接复用。
  3. Key 对比

    • reconcileChildren 中,通过 key 提升子节点的匹配效率,减少不必要的节点销毁和重建。
  4. 最小化 DOM 操作

    • React 在 workInProgress 树中完成所有计算,仅在提交阶段操作 DOM。

五、总结

  1. React 的 Fiber 树通过双缓存机制实现:

    • current:表示当前屏幕显示的状态。
    • workInProgress:在后台异步构建的新状态树。
    • 它们通过 alternate 属性连接,更新完成后切换树的角色。
  2. 构建 Fiber 树的过程包括:

    • beginWork 阶段:生成或复用 Fiber 节点,递归处理子节点。
    • completeWork 阶段:完成 DOM 节点创建并挂载子 DOM。
    • 提交阶段:执行 DOM 操作并切换 Fiber 树。
  3. Fiber 的设计提升了 React 的性能,使其能高效处理复杂更新任务和交互。

相关推荐
赵大仁27 分钟前
前端实时显示当前在线人数的实现
前端·javascript·ajax·json·html5
lfl1832616216034 分钟前
aspx触发html和ashx的交互
前端·html·交互
Libby博仙1 小时前
VUE3 常用的组件介绍
前端·javascript·vue.js·前端框架·npm·node.js
至少零下七度1 小时前
npm : 无法加载文件 D:\SoftFile\npm.ps1,因为在此系统上禁止运行脚本。
前端·npm·node.js
Super毛毛穗1 小时前
npm 与 pnpm:JavaScript 包管理工具的对比与选择
前端·javascript·npm
Libby博仙1 小时前
VUE3 VITE项目在 npm 中,关于 Vue 的常用命令有一些基础命令
前端·vue.js·npm·node.js
Aphasia3111 小时前
✍🏻记与vue生命周期⏱️的一次邂逅(短文📖)
前端·vue.js·面试
胤胤爸1 小时前
Android ndk-jni语法—— 4
android·java·前端
JINGWHALE11 小时前
设计模式 行为型 责任链模式(Chain of Responsibility Pattern)与 常见技术框架应用 解析
前端·人工智能·后端·设计模式·性能优化·系统架构·责任链模式
布兰妮甜2 小时前
Three.js 扩展与插件:增强3D开发的利器
javascript·3d·three.js·扩展与插件