从 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 的关联在哪里建立

第三站: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 映射。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐