2024年12月5日,react发布了react19版本。后面一段时间都将学习它的源码,并着手记录。
react官网:react19新特性
https://react.dev/blog/2024/12/05/react-19
在用vite创建react项目的使用,main.tsx
主文件都会有以下代码。
ts
//import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'
const root = createRoot(document.getElementById('root')!);
console.log('root',root)
root.render(
// <StrictMode>
<App />
// </StrictMode>,
)
该代码是整个项目的入口。

接下来我们就看看 createRoot 是如何执行。
createRoot 函数
createRoot
函数的主要作用是创建一个 React 应用的根节点,并对其进行一系列初始化操作,最终返回一个 ReactDOMRoot
对象。
ts
function createRoot(
container: Element | Document | DocumentFragment,
options?: CreateRootOptions,
): RootType {
// 用于控制是否默认启用并发更新
const concurrentUpdatesByDefaultOverride = false;
// 表示是否启用严格模式等。
let isStrictMode = false;
//
let identifierPrefix = '';
let onUncaughtError = defaultOnUncaughtError;
let onCaughtError = defaultOnCaughtError;
let onRecoverableError = defaultOnRecoverableError;
let transitionCallbacks = null;
//省略 options处理代码
// 创建容器对象 FiberRootNode
// FiberRootNode 对象,它是 React 协调器的核心数据结构,代表了整个 React 应用的根节点。
const root = createContainer(
container,
ConcurrentRoot,//ConcurrentRoot 表示使用并发模式进行渲染。
null,
isStrictMode,
concurrentUpdatesByDefaultOverride,
identifierPrefix,
onUncaughtError,
onCaughtError,
onRecoverableError,
transitionCallbacks,
);
//在dom container节点添加属性标记
// 调用 markContainerAsRoot 函数,在 DOM 容器节点上添加一些属性标记,用于标识该节点是 React 应用的根节点。
markContainerAsRoot(root.current, container);
// 处理容器元素
// 如果传入的 container 是一个注释节点,则将其父节点作为根容器元素;否则,直接使用 container 作为根容器元素。
const rootContainerElement: Document | Element | DocumentFragment =
container.nodeType === COMMENT_NODE //8 注释节点
? (container.parentNode: any)
: container;
// 事件委托处理
// 在div#root上绑定各种事件,包括捕获和冒泡阶段
// 可以实现事件委托,提高事件处理的效率。
listenToAllSupportedEvents(rootContainerElement);
// 根据创建的 FiberRootNode 对象 root,创建并返回一个 ReactDOMRoot 对象。这个对象提供了 render 方法,用于将 React 组件渲染到根节点上。
return new ReactDOMRoot(root);
}
createContainer 函数
调用 createFiberRoot
函数来创建一个 FiberRoot
对象并返回。
函数参数含义:
●
containerInfo
:类型为 Container,通常是一个 DOM 容器元素(如 div),用于指定 React 应用要挂载到的实际 DOM 节点。●
tag
:类型为 RootTag,用于标记根节点的类型,比如 ConcurrentRoot 表示使用并发模式渲染。●
hydrationCallbacks
:类型为 null | SuspenseHydrationCallbacks,在服务端渲染时,用于处理水合(hydration)过程中的回调函数。●
isStrictMode
:布尔类型,用于指示是否开启严格模式。严格模式会对组件进行额外的检查,帮助开发者发现潜在问题。●
concurrentUpdatesByDefaultOverride
:这个参数目前已被忽略,未来可能会移除。●
identifierPrefix
:字符串类型,用于为 React 元素生成唯一标识符的前缀。●
onUncaughtError
:错误处理回调函数,当发生未捕获的错误时会调用此函数。●
onCaughtError
:错误处理回调函数,当错误被捕获时调用,会提供更多错误信息,包括错误边界组件。●
onRecoverableError
:错误处理回调函数,当发生可恢复的错误时调用。●
transitionCallbacks
:类型为 null | TransitionTracingCallbacks,用于跟踪过渡(transition)状态的回调函数。
ts
function createContainer(
containerInfo: Container,// 实际的dom容器
tag: RootTag,// 渲染类型 并发模式或者传统模式
hydrationCallbacks: null | SuspenseHydrationCallbacks,
isStrictMode: boolean,
concurrentUpdatesByDefaultOverride: null | boolean,
identifierPrefix: string,
onUncaughtError: (
error: mixed,
errorInfo: {+componentStack?: ?string},
) => void,
onCaughtError: (
error: mixed,
errorInfo: {
+componentStack?: ?string,
+errorBoundary?: ?React$Component<any, any>,
},
) => void,
onRecoverableError: (
error: mixed,
errorInfo: {+componentStack?: ?string},
) => void,
transitionCallbacks: null | TransitionTracingCallbacks,
): OpaqueRoot {
// 设置为 false 表示不进行水合操作。水合操作通常用于服务端渲染,将服务端渲染的 HTML 与客户端的 React 应用进行连接。
const hydrate = false;
// 初始子元素,这里设置为 null,表示一开始没有初始的子元素。
const initialChildren = null;
//创建 FiberRoot
// createFiberRoot 函数创建 FiberRoot 对象,该函数会根据传入的参数初始化 FiberRoot 的各种属性,包括根节点的类型、挂载的 DOM 容器、错误处理回调等,最终返回一个代表整个 React 应用根节点的 FiberRoot 对象。
return createFiberRoot(
containerInfo,
tag,// 模式 并发模式
hydrate,
initialChildren,
hydrationCallbacks,
isStrictMode,
identifierPrefix,
onUncaughtError,
onCaughtError,
onRecoverableError,
transitionCallbacks,
null,
);
}
createFiberRoot 函数
createFiberRoot
函数是 React 中用于创建 FiberRoot
对象的核心函数,FiberRoot
是整个 React 应用的根节点,负责管理应用的渲染和更新流程。该函数会初始化根节点的各种属性,创建对应的 Fiber
节点,并进行一些状态和更新队列的初始化操作。
函数参数含义:
●
containerInfo
:通常是一个 DOM 容器元素,用于指定 React 应用要挂载到的实际 DOM 节点。●
tag
:标记根节点的类型,如 ConcurrentRoot 表示使用并发模式渲染。●
hydrate
:布尔值,指示是否进行水合操作(用于服务端渲染)。●
initialChildren
:初始的子元素列表。●
hydrationCallbacks
:在水合过程中使用的回调函数。●
isStrictMode
:布尔值,指示是否开启严格模式。●
identifierPrefix
:用于为 React 元素生成唯一标识符的前缀。●
onUncaughtError
:未捕获错误的处理回调函数。●
onCaughtError
:已捕获错误的处理回调函数。●
onRecoverableError
:可恢复错误的处理回调函数。●
transitionCallbacks
:用于跟踪过渡状态的回调函数。●
formState
:表单状态信息。
ts
function createFiberRoot(
containerInfo: Container,// 实际的dom容器
tag: RootTag,// 渲染模式 并发模式或者传统模式
hydrate: boolean,
initialChildren: ReactNodeList,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
isStrictMode: boolean,// 示范严格模式
identifierPrefix: string,// 前缀
onUncaughtError: (
error: mixed,
errorInfo: {+componentStack?: ?string},
) => void,
onCaughtError: (
error: mixed,
errorInfo: {
+componentStack?: ?string,
+errorBoundary?: ?React$Component<any, any>,
},
) => void,
onRecoverableError: (
error: mixed,
errorInfo: {+componentStack?: ?string},
) => void,
transitionCallbacks: null | TransitionTracingCallbacks,
formState: ReactFormState<any, any> | null,
): FiberRoot {
// 创建 FiberRootNode 实例
// 创建一个 FiberRootNode 实例,该实例代表整个 React 应用的根节点,包含了与 DOM 容器、根节点类型、错误处理等相关的信息。
const root: FiberRoot = (new FiberRootNode(
containerInfo,
tag,// 并发模式
hydrate,
identifierPrefix,
onUncaughtError,
onCaughtError,
onRecoverableError,
formState,
): any);
if (enableSuspenseCallback) {
// 设置水合回调函数
root.hydrationCallbacks = hydrationCallbacks;
}
if (enableTransitionTracing) {
// 设置过渡跟踪回调函数
root.transitionCallbacks = transitionCallbacks;
}
// 创建 Fiber 节点,该节点代表根组件的 Fiber 节点。
const uninitializedFiber = createHostRootFiber(tag, isStrictMode);
//root.current 指向当前的 Fiber 节点,建立 FiberRoot 到 Fiber 节点的引用。
root.current = uninitializedFiber;
//uninitializedFiber.stateNode 指向 FiberRoot,建立 Fiber 节点到 FiberRoot 的引用。
uninitializedFiber.stateNode = root;
// 根据是否启用缓存,初始化 Fiber 节点的状态。状态对象包含初始子元素、是否水合以及缓存信息。
if (enableCache) {
// 创建缓存对象
const initialCache = createCache();
// 保留缓存引用
retainCache(initialCache);
// 将缓存对象赋值给根节点的 pooledCache 属性
root.pooledCache = initialCache;
// 再次保留缓存引用
retainCache(initialCache);
// 初始化根 Fiber 节点的状态
const initialState: RootState = {
element: initialChildren,//存储初始的子元素列表 initialChildren,这些子元素是 React 应用开始渲染时的初始内容。
isDehydrated: hydrate,//一个布尔值,用于指示是否处于水合状态,其值来源于 hydrate 参数。
cache: initialCache,// 存储前面创建的缓存对象 initialCache,这样根 Fiber 节点就可以访问这个缓存对象。
};
// 存储前面创建的缓存对象 initialCache,这样根 Fiber 节点就可以访问这个缓存对象。
// memoizedState 用于存储 Fiber 节点的状态,后续在渲染和更新过程中,React 会根据这个状态来决定如何渲染组件。
uninitializedFiber.memoizedState = initialState;
} else {
const initialState: RootState = {
element: initialChildren,
isDehydrated: hydrate,
cache: (null: any), // not enabled yet
};
uninitializedFiber.memoizedState = initialState;
}
// 初始化更新队列
// 调用 initializeUpdateQueue 函数,为 Fiber 节点初始化更新队列,用于管理后续的状态更新操作。
initializeUpdateQueue(uninitializedFiber);
// 返回 FiberRoot 对象
return root;
}
fiberRoot
节点与 fiber
节点的关系:
fiberRoot
的current
属性 是根节点的fiber
对象的引用。

createHostRootFiber 函数
创建一个根 Fiber
节点,该节点代表整个 React 应用的根。在创建过程中,会根据不同的tag
模式(如传统模式、并发模式)以及是否开启严格模式和性能分析器等条件,来设置 Fiber
节点的 mode 属性,最后调用 createFiber
函数完成 Fiber
节点的创建。
函数参数含义:
tag
,类型为 RootTag,用于标记根节点的类型。tag 的值可能为传统模式(值为 0)或并发模式(ConcurrentRoot,值为 1)。isStrictMode
,布尔类型,指示是否开启严格模式。严格模式会对组件进行额外的检查,帮助开发者发现潜在问题。
ts
function createHostRootFiber(
tag: RootTag,
isStrictMode: boolean,
): Fiber {
//设置 mode 属性,用于存储 Fiber 节点的模式。
let mode;
//disableLegacyMode常量为true
if (disableLegacyMode || tag === ConcurrentRoot) {
mode = ConcurrentMode; // 并发模式
// 是否严格模式(只有开发环境与藕可能为true)
// if (isStrictMode === true) {
// mode |= StrictLegacyMode | StrictEffectsMode;
// }
} else {
mode = NoMode;// NoMode默认为0 即传统模式
}
// enableProfilerTimer表示启用性能分析器,isDevToolsPresent表示开发者工具存在
// if (enableProfilerTimer && isDevToolsPresent) {
// 相当于 mode = mode | ProfileMode 例如 (1 |2) = 3
// mode |= ProfileMode;
// }
//创建根 Fiber 节点,HostRoot常量为3
return createFiber(HostRoot, null, null, mode);
}
initializeUpdateQueue 函数
initializeUpdateQueue
函数的功能是为一个 Fiber
节点初始化更新队列。
UpdateQueue<State>
类型的对象queue
,这个对象包含了更新队列的各种属性:
baseState
:初始状态,赋值为 fiber.memoizedState,memoizedState 存储了当前 Fiber 节点的最新状态。firstBaseUpdate
和lastBaseUpdate
:分别指向更新队列中第一个和最后一个基础更新,初始值都为 null。基础更新是指那些已经被处理过,但由于某些原因(如优先级问题)还没有应用到 baseState 上的更新。shared
:是一个包含共享信息的对象,其中:
pending
:指向待处理的更新链表的尾部,初始值为 null。lanes
:表示更新的优先级,初始值为 NoLanes,代表没有任何优先级。hiddenCallbacks
:用于存储隐藏的回调函数,初始值为 null。callbacks
:用于存储更新完成后的回调函数,初始值为 null。
ts
function initializeUpdateQueue<State>(fiber: Fiber): void {
const queue: UpdateQueue<State> = {
baseState: fiber.memoizedState,
firstBaseUpdate: null,
lastBaseUpdate: null,
shared: {
pending: null,
lanes: NoLanes,
hiddenCallbacks: null,
},
callbacks: null,
};
// 将创建好的更新队列 queue 赋值给 fiber 节点的 updateQueue 属性,这样 Fiber 节点就有了自己的更新队列,后续的状态更新操作可以通过这个队列来进行管理。
fiber.updateQueue = queue;
}
ReactDOMRoot 构造函数
ReactDOMRoot
构造函数的主要作用是创建一个 ReactDOMRoot
实例,并将传入的 FiberRoot
对象存储在实例的 _internalRoot
属性中。
ts
function ReactDOMRoot(internalRoot: FiberRoot) {
this._internalRoot = internalRoot;
}
ReactDOMRoot.prototype.render 函数
render
是ReactDOMRoot
原型上的一个方法,主要作用是在根 DOM 节点上渲染一个 React
元素。
ts
ReactDOMHydrationRoot.prototype.render = ReactDOMRoot.prototype.render =
// $FlowFixMe[missing-this-annot]
function (children: ReactNodeList): void {
const root = this._internalRoot;
if (root === null) {
throw new Error('Cannot update an unmounted root.');
}
//执行更新
updateContainer(children, root, null, null);
};
ReactDOMRoot.prototype.unmount 函数
unmount
方法是ReactDOMRoot
原型上的一个方法,其主要作用是卸载 React
应用的根节点,清理相关资源,将根节点从 DOM 中移除,释放内存并确保应用不再占用相关资源。
ts
ReactDOMHydrationRoot.prototype.unmount = ReactDOMRoot.prototype.unmount =
// $FlowFixMe[missing-this-annot]
function (): void {
// 获取内部根节点实例
const root = this._internalRoot;
// 存在
if (root !== null) {
// 清空根实例的引用
this._internalRoot = null;
// root.containerInfo 存储了 React 应用渲染的 DOM 容器节点信息。通过 root.containerInfo 获取根节点对应的 DOM 容器节点。
const container = root.containerInfo;
// 同步更新容器
updateContainerSync(null, root, null, null);
// 刷新同步工作
flushSyncWork();
// 取消容器的根节点标记
unmarkContainerAsRoot(container);
}
};
全局变量
ts
const randomKey = Math.random().toString(36).slice(2);
//internalInstanceKey 用于在 DOM 元素上存储 React Fiber 实例的相关信息。
const internalInstanceKey = '__reactFiber$' + randomKey;
// internalPropsKey 用于存储传递给组件的 props 信息。
const internalPropsKey = '__reactProps$' + randomKey;
const internalContainerInstanceKey = '__reactContainer$' + randomKey;
// internalEventHandlersKey 用于存储事件处理函数的相关信息。
const internalEventHandlersKey = '__reactEvents$' + randomKey;
const internalEventHandlerListenersKey = '__reactListeners$' + randomKey;
const internalEventHandlesSetKey = '__reactHandles$' + randomKey;
const internalRootNodeResourcesKey = '__reactResources$' + randomKey;
const internalHoistableMarker = '__reactMarker$' + randomKey;
工具函数 markContainerAsRoot
markContainerAsRoot
的作用是将一个 DOM 容器节点标记为 React 应用的根容器,并将对应的 Fiber
根节点与该容器节点关联起来。在 React 的渲染过程中,需要将 Fiber
树与实际的 DOM
节点进行关联。
函数参数含义:
hostRoot
, 根节点fibernode
, DOM 容器节点
ts
function markContainerAsRoot(hostRoot: Fiber, node: Container): void {
// $FlowFixMe[prop-missing]
node[internalContainerInstanceKey] = hostRoot;
// 变量internalContainerInstanceKey = '__reactContainer$' + randomKey;
}

工具函数 markContainerAsRoot
ts
function unmarkContainerAsRoot(node: Container): void {
// $FlowFixMe[prop-missing]
node[internalContainerInstanceKey] = null;
}
流程图

后续继续看FiberRoot
节点和Fiber
节点的结构以及root.render
中的updateContainer
是如何执行的。