Skip to content

如何有效地阅读 React 源码

1. 阅读前的准备

关于行号引用:本仓库所有文档中的源码行号(如 ReactFiberHooks.js:1948)对应 2026 年 8 月 React 官方仓库 main 分支快照(ReactVersion = 19.3.0 开发版)。随着 React 主分支持续推进 commit,行号可能逐渐偏移——建议以函数名而非行号为搜索锚点,行号仅用于辅助定位。

1.1 环境准备

bash
# 克隆源码
git clone https://github.com/facebook/react.git
cd react

# 安装依赖
yarn install

# 构建(可选,用于调试)
yarn build

1.2 推荐工具

  • VS Code:配合 Flow 类型检查扩展
  • Chrome DevTools:断点调试
  • React DevTools:观察组件树和 Profiler
  • CodeTour(VS Code 扩展):源码路径标注

2. 阅读策略

2.1 不要从头到尾读

React 源码有数万行,线性阅读会迷失。带着问题找答案是更有效的方式:

错误方式:
  从 ReactFiberWorkLoop.js 第一行开始读 → 迷失在数千行代码中

正确方式:
  问题:「setState 后 React 做了什么?」
  → 从 ReactBaseClasses.js 的 setState → updater.enqueueSetState
  → ReactFiberConcurrentUpdates.js → scheduleUpdateOnFiber
  → ReactFiberRootScheduler.js → ensureRootIsScheduled
  → scheduler/Scheduler.js → scheduleCallback
  → 回到 ReactFiberWorkLoop.js 的 performConcurrentWorkOnRoot
  → workLoopConcurrentByScheduler → performUnitOfWork → beginWork → completeWork → commit

  只读这条链路上的关键函数,忽略旁支。

2.2 从入口跟踪调用链

使用 VS Code 的"Go to Definition"和"Find All References"跟踪调用链:

setState 怎么触发渲染?
  1. ReactBaseClasses.js: this.setState → this.updater.enqueueSetState
  2. ReactFiberClassComponent.js: enqueueSetState → 创建 Update
  3. ReactFiberConcurrentUpdates.js: enqueueUpdate → 加入队列
  4. ReactFiberWorkLoop.js: scheduleUpdateOnFiber(root, fiber, lane) → markRootUpdated (ReactFiberLane.js)
  5. ReactFiberRootScheduler.js: ensureRootIsScheduled → scheduleCallback
  6. Scheduler.js: push(taskQueue, task) → requestHostCallback
  7. MessageChannel → flushWork → performConcurrentWorkOnRoot
  8. ReactFiberWorkLoop.js: renderRootConcurrent → workLoopConcurrentByScheduler
  9. performUnitOfWork → beginWork → completeWork
  10. commitRoot → commitMutationEffects → DOM 更新

2.3 用断点辅助理解

在 Chrome 中调试 React 源码:

  1. fixtures/concurrent/ 下的 demo 应用
  2. yarn build 构建开发版本
  3. 在 Chrome DevTools 中打开 Source 面板
  4. 在关键函数设断点(如 performUnitOfWorkbeginWork
  5. 触发更新(点击按钮),观察调用栈

2.4 关注注释

React 源码的注释质量很高,很多关键设计都有详细说明:

javascript
// ReactFiber.js:326-330
// We use a double buffering pooling technique because we know that we'll
// only ever need at most two versions of a tree. We pool the "other" unused
// node that we're free to reuse. This is lazily created to avoid allocating
// extra objects for things that are never updated.

2.5 关注 Feature Flags

React 源码中大量使用 Feature Flags 控制行为:

javascript
if (enableProfilerTimer) { ... }
if (enableViewTransition) { ... }
if (disableLegacyMode) { ... }

阅读时忽略被 flag 关闭的分支,只关注核心路径。

3. 推荐阅读顺序

阶段 1(建立全局认知):
  → 00-overview 三篇文档
  → ReactFiberWorkLoop.js 的 workLoop 和 performUnitOfWork
  → 理解"递归"和"归"的整体流程

阶段 2(深入数据结构):
  → ReactInternalTypes.js(Fiber 和 FiberRoot 的类型定义)
  → ReactWorkTags.js(了解所有组件类型)
  → ReactFiberFlags.js(了解所有副作用标记)
  → ReactFiberLane.js(了解优先级模型)

阶段 3(理解渲染流程):
  → ReactFiberBeginWork.js(beginWork 的 switch 分支)
  → ReactChildFiber.js(Diff 算法)
  → ReactFiberCompleteWork.js(DOM 创建)
  → ReactFiberCommitWork.js(DOM 更新)

阶段 4(理解 Hooks):
  → ReactFiberHooks.js(先读 mountState/updateState)
  → 理解 hooks 链表的工作方式

阶段 5(理解调度):
  → scheduler/Scheduler.js
  → SchedulerMinHeap.js

阶段 6(进阶):
  → ReactFiberThrow.js(错误处理)
  → ReactFiberSuspenseComponent.js(Suspense)
  → RSC 相关源码

4. 实践检验

每读完一个主题,用以下方式检验理解:

  1. 能画出流程图吗? 在纸上画出该主题的数据流/控制流
  2. 能解释给同事听吗? 用自己的语言叙述核心机制
  3. 能做对应的实践练习吗? 完成 practices/ 中的对应练习
  4. 能在源码中找到答案吗? 遇到实际问题时能定位到源码

5. 常见误区

误区 1:「我需要理解每一行代码」
  → 不需要。先理解 20% 的核心代码,它们覆盖了 80% 的行为。

误区 2:「源码必须在线读」
  → 本地 clone 后用 VS Code 更好:可以搜索、跳转、断点。

误区 3:「从 v15 开始读更容易」
  → 不推荐。v15 的 Stack Reconciler 与现代 React 差异太大。
     直接读 Fiber 架构的代码,对照本仓库的文档理解。

误区 4:「先读完所有源码再写代码」
  → 交替进行更好。读源码 → 写实践代码 → 再读源码 → 再写代码。
     实践是检验理解的唯一方式。

下一步

参考资料

Released under the MIT License.