React 源码解读流程:从入口到渲染的全链路揭秘

React 是目前前端最流行的框架之一,但很多开发者只会停留在使用层面,对于 React 内部是如何运作的缺乏深入理解。本文将带你从源码角度出发,梳理 React 的运行流程,帮助你建立整体认知。


一、源码结构概览

在深入分析之前,我们需要知道 React 源码大致分为以下几个部分:

  • react:核心 API(useStateuseEffect 等 hooks,以及 createElement 等方法)。
  • react-dom:负责 DOM 渲染相关逻辑,包括调和(reconciliation)、Fiber 架构实现等。
  • scheduler:调度优先级,决定任务的执行顺序。
  • shared:共享工具方法和常量。

了解目录结构有助于我们在阅读源码时快速定位。


二、React 启动流程

当我们在应用里写下:

import React from "react";
import ReactDOM from "react-dom";

ReactDOM.render(<App />, document.getElementById("root"));

那么内部会经历怎样的流程呢?

1. ReactDOM.render

  • 入口位于 react-dom 包。
  • 会调用 legacyRenderSubtreeIntoContainer → renderSubtreeIntoContainer → 最终进入 createRoot(React 18 以后则推荐使用 createRoot API)。

2. 创建 FiberRoot

  • React 会为整个应用创建一个 FiberRoot,它是 Fiber 架构的根节点。
  • 每个组件会对应一个 FiberNode

3. 开始初次渲染

  • 初次渲染走 同步模式,即直接构建 Fiber 树并渲染到 DOM。
  • 过程中会执行组件函数,调用 Hooks,得到虚拟 DOM。

三、Fiber 架构与调和流程

1. 什么是 Fiber?

Fiber 是 React 内部表示 UI 的数据结构,每个 Fiber 节点对应一个 React 元素。它的本质是一个对象:

function FiberNode(tag, pendingProps, key) {
  this.tag = tag;              // 组件类型(函数组件、类组件、原生节点)
  this.key = key;              // diff 算法用的 key
  this.type = null;            // 元素类型(如 div、span)
  this.stateNode = null;       // 对应的 DOM 节点
  this.return = null;          // 父 Fiber
  this.child = null;           // 第一个子 Fiber
  this.sibling = null;         // 下一个兄弟 Fiber
  this.pendingProps = pendingProps;
  this.memoizedProps = null;   // 已渲染的 props
  this.alternate = null;       // 双缓存树结构中的“镜像”
}

可以看到,每个 Fiber 节点都维护了父子兄弟关系,从而形成一颗树结构。

2. Fiber 的双缓存树

React 使用 current Fiber Tree 和 workInProgress Fiber Tree 来保存状态:

  • current:当前已渲染到页面上的 Fiber 树
  • workInProgress:正在构建的新 Fiber 树

更新完成后,React 会用 workInProgress 替换 current,从而完成一次渲染。

3. 调度与优先级

React 使用 scheduler 包来实现任务调度:

  • 同步任务:如用户输入
  • 异步任务:如网络请求完成后的状态更新

Fiber 可以被中断,当有更高优先级任务进来时,React 会暂停低优先级任务,先执行高优先级任务。


4. Fiber 渲染流程

整体流程可以简化为以下几步:

  1. 开始阶段(Begin Work)

    • 为每个 Fiber 节点创建子节点
    • 执行 render 或 function component 的逻辑
  2. 完成阶段(Complete Work)

    • 确认 Fiber 节点的 DOM 操作
    • 生成 Effect List
  3. 提交阶段(Commit)

    • 执行 DOM 更新
    • 执行生命周期函数(componentDidMount / useEffect

5. Fiber 渲染流程示意图

 ┌───────────────────┐
 │   Begin Work 阶段 │
 └─────┬─────────────┘
       ↓
 ┌───────────────────┐
 │ Complete Work 阶段│
 └─────┬─────────────┘
       ↓
 ┌───────────────────┐
 │   Commit 阶段     │
 └───────────────────┘

6. Fiber 的作用

  • 链表结构:每个 FiberNode 保存对父节点、子节点、兄弟节点的引用。
  • 可中断渲染:React 将渲染拆解为任务片段,可以被打断和恢复。

7. Reconciliation(调和)

  • 对比新旧 Fiber 树,找出需要更新的节点(Diff 算法)。
  • 生成 effect list(副作用链表),记录需要对 DOM 做的操作。

8. Commit 阶段

分为三个小步骤:

  • before mutation:在 DOM 变更前执行(比如 getSnapshotBeforeUpdate)。
  • mutation:执行 DOM 更新。
  • layout:调用 componentDidMountuseLayoutEffect 等。

四、Hooks 的执行原理

以 useState 为例:

  1. 初次渲染时,React 会在 FiberNode 上建立一个 hook 链表,每个 hook 保存状态。
  2. useState(initialState) 会返回一个 [state, dispatch]
  3. 当调用 dispatch 时,会创建一个 update 对象,放入更新队列。
  4. 下次渲染时,从队列里取出最新状态,计算后替换。

这也是为什么 hook 必须写在函数组件最外层,不能在 if/else 里写 —— React 需要保证 hook 顺序一致。


五、Scheduler 调度

React 并不是所有任务都立即执行,而是根据优先级:

  • Immediate:立即执行(比如用户输入)。
  • User-blocking:高优先级(比如按钮点击)。
  • Normal:普通渲染任务。
  • Low / Idle:低优先级任务。

Scheduler 通过 requestIdleCallbackMessageChannel 等机制实现任务切片,让渲染更流畅。


六、整体流程图

ReactDOM.render
   ↓
创建 FiberRoot → 创建 Fiber 树
   ↓
Render 阶段(调和:Diff 算法,构建 Fiber 树)
   ↓
Commit 阶段(DOM 更新,调用生命周期/Effect)
   ↓
Scheduler 负责调度优先级

七、总结

React 源码解读的核心在于三个关键点:

  1. Fiber 架构:链表化数据结构,支持可中断渲染。
  2. 调和 & 提交:Diff 算法找出变化,commit 阶段更新 DOM。
  3. Scheduler 调度:任务分片与优先级控制,提升流畅度。

如果你想深入研究 React 源码,可以从 react-reconciler 和 scheduler 两个包入手,配合调试工具一步步跟踪调用链路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值