React源码阅读顺序建议
中的 createContainer/updateContainer→转入 .old 文件,沿着 WorkLoop.old → BeginWork.old → CompleteWork.old → CommitWork.old 把一次渲染的生命周期走通。练习3:在 ReactFiberLane.old.js 里找离散事件相关的 Lane 与优先级,回到 ReactEventPriorities.o
从 ReactDOM 入口开始读,是最容易把“React API → DOM 渲染 → Fiber 调和”这条主线串起来的切入点。下面是一条可执行的阅读路线和每一步要关注的关键点,全部对应到你仓库中的真实文件,建议按顺序边读边画流程图。
第一站:确认对外 API 和入口映射
- 读包入口,明白外部 API 都从哪里来
-
index.js
- 看点:
-
这里导出的 createRoot、hydrateRoot、render/hydrate 等,全部转发到 ReactDOM 源码。
-
-
- 读客户端总入口(最重要)
-
ReactDOM.js
- 看点:
-
public API 映射:render/hydrate/unstable_renderSubtreeIntoContainer/unmountComponentAtNode → 走 legacy 路径(React 17 兼容)
-
createRoot/hydrateRoot → 走 concurrent 路径(React 18)
-
createPortal 的来源(来自 reconciler)
-
flushSync、batchedUpdates、discreteUpdates 等调和器 API 是如何向外暴露的
-
injectIntoDevTools 的注入时机(了解 DevTools 如何接入)
-
-
第二站:React 18 的根容器(Concurrent Root)
- 新根 API 的实现与容器生命周期
-
ReactDOMRoot.js
- 看点:
- createRootImpl / hydrateRootImpl 做了什么初始化:
-
调用 reconciler 的 createContainer / hydrateContainer
-
在容器上注册所有支持的 DOM 事件(listenToAllSupportedEvents)
-
组装 root 实例,root.render → updateContainer
-
-
root.unmount / root.render 的职责边界
-
容器与 fiberRoot 的关联在哪里建立
- createRootImpl / hydrateRootImpl 做了什么初始化:
-
第三站:Legacy 入口(向后兼容)
- 老 API 的桥接与兼容
-
ReactDOMLegacy.js
- 看点:
-
render/hydrate 如何创建 legacy root 并调 reconcile
-
unmountComponentAtNode 的卸载路径
-
这条路径与 createRoot 的差异(优先级、特性、事件初始化)
-
-
第四站:宿主环境与事件系统(DOM 层如何与调和器衔接)
- DOM 操作的“宿主配置”
-
ReactDOMHostConfig.js
- 看点:
-
宿主接口,如 appendChild、insertBefore、commitUpdate、resetTextContent 等,commit 阶段会调用这些
-
findHostInstance、getPublicInstance 等与外部 API 的交汇点
-
-
- 事件系统(理解为什么 createRoot 会“先装事件”)
-
DOMPluginEventSystem.js
-
ReactDOMEventListener.js
-
ReactDOMEventHandle.js
- 看点:
-
listenToAllSupportedEvents 如何在 root container 上注册事件
-
离散事件/连续事件及其优先级与调和器的衔接(attemptDiscreteHydration 等)
-
unstable_createEventHandle 的作用与限制
-
-
第五站:进入 Reconciler(被 ReactDOM 调用的“引擎室”)
- 入口与分流(old/new 调和器)
-
ReactFiberReconciler.js
- 看点:
-
这是一个“汇总/转发层”,根据 feature flag 转到 .old 或 .new 真正实现
-
你的仓库默认 enableNewReconciler=false,建议优先读 .old 文件,.new 作为对照
-
-
- 容器、优先级与工作循环(按 .old 主线)
-
ReactFiberRoot.old.js
(root 结构、初始化) -
ReactFiberLane.old.js
(Lane/优先级模型,强烈建议先读) -
ReactFiberWorkLoop.old.js
(render/commit 的大循环) -
ReactFiberBeginWork.old.js
(向下:为子节点创建/对比 fiber) -
ReactFiberCompleteWork.old.js
(向上:收集副作用、准备 DOM 操作数据) -
ReactFiberCommitWork.old.js
(提交:真正调用 HostConfig 做 DOM 变更)
-
第六站:调度器(Reconciler 何时/以何优先级执行)
- 先看数据结构与优先级
-
SchedulerPriorities.js
-
SchedulerMinHeap.js
-
- 再看平台 fork(实际运行实现)
-
Scheduler.js
-
看点:不同环境(postTask、MessageChannel、setTimeout)下的调度策略选择
-
如何边读边“串起来”(推荐这样操作)
-
在
ReactDOM.js
中定位 createRoot/hydrateRoot 的导出→跳转到ReactDOMRoot.js
看初始化→继续跳转到ReactFiberReconciler.js
中的 createContainer/updateContainer→转入 .old 文件,沿着 WorkLoop.old → BeginWork.old → CompleteWork.old → CommitWork.old 把一次渲染的生命周期走通。 -
回到
ReactDOMHostConfig.js
对照 Commit 阶段的每个 DOM 操作,看提交到底做了什么。 -
对照事件系统(DOMPluginEventSystem + ReactDOMEventListener),理解为何一开始要在 root 上挂全集事件监听,以及事件如何带着优先级影响更新。
可选:一步一个小目标的“练习题”
- 练习1:只跟踪 createRoot(container).render(
) 这条同步路径,标出每个函数所在文件与职责。
-
练习2:在 DOMPluginEventSystem 中找 listenToAllSupportedEvents,回到 ReactDOMRoot 查看它在哪被调用,理解“先注册事件再渲染”的动机。
-
练习3:在 ReactFiberLane.old.js 里找离散事件相关的 Lane 与优先级,回到 ReactEventPriorities.old.js 对照事件→lane 映射。
更多推荐
所有评论(0)