一般我们都会从createRoot开始入手分析react的源码 ReactDOM.createRoot(rootElement).render();
create
流程图
graph TD
A[createRoot] --> B{判断是否合法容器}
B -->|Yes| C[createContainer 创建容器]
B -->|No| D[报错]
C -->E[createFiberRoot 创建根节点,实例一个根fiber]
E -->F[createHostRootFiber 创建主机节点并指向根节点的current]
F -->G[initializeUpdateQueue 初始化根节点进入更新队列]
1. createRoot
实际调用的是createRootImpl方法,传入创建的节点和参数
// 创建根节点的工具函数
function createRoot(
container: Element | Document | DocumentFragment,
options?: CreateRootOptions,
): RootType {
...
return createRootImpl(container, options);
}
2. createRootImpl
负责调用创建容器方法,根据enableNewReconciler判断调用createContainer_new还是createContainer_old;
enableNewReconciler的主要作用是启用React的新Reconciler实现
该容器将负责将虚拟 DOM(即组件树)与真实 DOM 对接起来
createContainer,通过enableNewReconciler 判断是否开去新调和旧的reconciler,后续通过createFiberRoot方法去创建根节点
function createRootImpl(
container: Element | Document | DocumentFragment,
options?: CreateRootOptions,
) {
//首先判断是否合法容器
//options 设置变量
...
const root = createContainer(
container,
ConcurrentRoot,
null,
isStrictMode,
concurrentUpdatesByDefaultOverride,
identifierPrefix,
onRecoverableError,
transitionCallbacks,
);
}
listenToAllSupportedEvents(rootContainerElement);
return new ReactDOMRoot(root);
3. createFiberRoot
创建根节点,返回一个FiberRoot对象
//fiberRootNode是一个根结点构造函数,创建的是一个实例
function FiberRootNode(
containerInfo,
tag,
hydrate,
identifierPrefix,
onRecoverableError,
) {
this.tag = tag; // 根节点标签
this.containerInfo = containerInfo; // 容器信息
this.pendingChildren = null; // 挂起的子节点
this.current = null; // 当前 Fiber 节点
this.pingCache = null; // ping 缓存
this.finishedWork = null; // 已完成的工作
this.timeoutHandle = noTimeout; // 超时句柄
this.context = null; // 上下文
this.pendingContext = null; // 挂起的上下文
this.callbackNode = null; // 回调节点
this.callbackPriority = NoLane; // 回调优先级
this.eventTimes = createLaneMap(NoLanes); // 事件时间
this.expirationTimes = createLaneMap(NoTimestamp); // createLaneMap 存储过期时间的映射,react 中lane 是用来标识更新优先级的位掩码,它可以在频繁运算的时候占用内存少,计算速度快。每个 lane 代表一种优先级级别 totalLanes = 31 初始值均为-1
this.pendingLanes = NoLanes; // 挂起的 Lane
this.suspendedLanes = NoLanes; // 挂起的 Lane
this.pingedLanes = NoLanes; // ping 的 Lane
this.expiredLanes = NoLanes; // 过期的 Lane
this.mutableReadLanes = NoLanes; // 可变的读取 Lane
this.finishedLanes = NoLanes; // 已完成的 Lane
this.entangledLanes = NoLanes; // 纠缠的 Lane
this.entanglements = createLaneMap(NoLanes); // 纠缠关系
this.identifierPrefix = identifierPrefix; // 标识符前缀
this.onRecoverableError = onRecoverableError; // 可恢复错误的回调
}
function createFiberRoot(
containerInfo: Container,
tag: RootTag,
hydrate: boolean,
){
//创建FiberRoot节点
const root = new FiberRootNode(containerInfo, tag, hydrate);
//创建一个主机根节点的Fiber节点,将root的current设置为该主机fiber
const uninitializedFiber = createHostRootFiber(
tag,
isStrictMode,
concurrentUpdatesByDefaultOverride,
);
// 建立FiberRoot与RootFiber之间的联系
root.current = uninitializedFiber; // 设置当前 Fiber 节点
uninitializedFiber.stateNode = root; // 设置 Fiber 节点的 stateNode
...
// 对于HostRoot或者ClassComponent会使用initializeUpdateQueue创建updateQueue,
// 然后将updateQueue挂载到fiber节点上
initializeUpdateQueue(uninitializedFiber);
return root;
}
//创建一个主机根节点的Fiber节点
function createHostRootFiber(
tag: RootTag,
isStrictMode: boolean,
concurrentUpdatesByDefaultOverride: boolean | null,
){
//创建一个新节点
return createFiber(HostRoot, null, null, mode);
}
4.createFiber
创建节点 ,返回一个fiber对象 fiber对象通过return、sibling、child指向,来构建完整的fiber树,各个节点包含了类型、父级、子级、兄弟节点、lanes级别(调度级别)、alternate(备用节点)等属性
function createFiber(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
){
return new FiberNode(tag, pendingProps, key, mode);
}
/**
* FiberNode 构造函数,用于创建一个新的 Fiber 节点。
* @param {WorkTag} tag - Fiber 节点的标签,表示节点的类型
* @param {mixed} pendingProps - 挂起的属性
* @param {null | string} key - 节点的 key
* @param {TypeOfMode} mode - 节点的模式
*/
function FiberNode(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
// 实例属性
this.tag = tag; // 节点标签
this.key = key; // 节点 key
this.elementType = null; // 元素类型
this.type = null; // 节点类型
this.stateNode = null; // 节点对应的 DOM 节点或组件实例
// Fiber 属性
this.return = null; // 父节点 通过这个属性来构建一个树状结构,每个节点都有一个父节点和子节点,通过这个属性可以找到父节点和子节点
this.child = null; // 第一个子节点 通过这个属性可以找到第一个子节点
this.sibling = null; // 兄弟节点 通过这个属性可以找到兄弟节点
this.index = 0; // 节点在父节点中的索引 通过这个属性可以找到节点在父节点中的索引
this.ref = null; // 节点的 ref
this.pendingProps = pendingProps; // 挂起的属性
this.memoizedProps = null; // 记忆的属性
this.updateQueue = null; // 更新队列
this.memoizedState = null; // 记忆的状态
this.dependencies = null; // 依赖项
this.mode = mode; // 节点模式
// 副作用标志
this.flags = NoFlags; // 节点的标志
this.subtreeFlags = NoFlags; // 子树的标志
this.deletions = null; // 待删除的节点
this.lanes = NoLanes; // 节点的 Lane
this.childLanes = NoLanes; // 子节点的 Lane
this.alternate = null; // 备用节点
}
5.initializeUpdateQueue
当根节点创建成功后,需要初始化更新队列,给fiber添加updateQueue更新属性。
updateQueue是React状态更新相关的数据结构
其中shared.pending保存当前待执行的更新,比如1 ==> 2,其中baseState就是1,pending就是2
我们后面可以通过优先级lane来调度这些更新,执行对应的待执行pending
//初始化更新队列
function initializeUpdateQueue<State>(fiber: Fiber): void {
const queue: UpdateQueue<State> = {
baseState: fiber.memoizedState, //当前fiber的初始化状态
firstBaseUpdate: null, //初始化更新链表指针
lastBaseUpdate: null,
shared: {
pending: null, //创建共享更新队列(环形链表结构)
lanes: NoLanes, //初始化lane
},
effects: null,//初始化副作用数组
};
fiber.updateQueue = queue;
}
到此创建了根节点FiberRoot,他是fiber结构的最外层对象,在应用里至少有一个,它通过current属性与rootFiber关联。
rootFiber表示组件对应的fiber对象,可以有多个,通过stateNode指向fiberRoot。
我们创建完根节点后,初始化创建了一个更新对象,用于存放初始值、优先级、待执行更新等
紧接着,react会调用listenToAllSupportedEvents托管浏览器方法对其实行监听
6.listenToAllSupportedEvents
是React事件系统的核心逻辑之一,主要负责在DOM根节点上注册所有支持的事件监听器
listeningMarker是是否正在监听标识,判断是否存在可以防止重复监听
react通过事件注册系统,给allNativeEvents注册事件
SimpleEventPlugin.registerEvents(); // 基础事件(click/keypress等)
EnterLeaveEventPlugin.registerEvents(); // 鼠标进入/离开事件
ChangeEventPlugin.registerEvents(); // 处理表单变更事件
SelectEventPlugin.registerEvents(); // 处理<select>元素事件
BeforeInputEventPlugin.registerEvents(); // 处理输入前事件
nonDelegatedEvents定义了不能代理的事件,如下
//定义nonDelegatedEvents 不能通过委托方式处理的事件
nonDelegatedEvents: Set<DOMEventName> = new Set([
'cancel',
'close',
'invalid',
'load',
'scroll',
'toggle',
...mediaEventTypes,
]);
listenToAllSupportedEvents 函数主要遍历各个事件,进行对应的分发处理
针对非selectionchange的事件,进行冒泡和捕获阶段的监听
selectionchange事件,对冒泡进行监听
本质实际到最后还是通过addEventListener对事件进行监听
export function listenToAllSupportedEvents(rootContainerElement: EventTarget) {
//防止重复监听
if (rootContainerElement[listeningMarker]) {
return;
}
rootContainerElement[listeningMarker] = true;
//遍历 allNativeEvents 集合(包含所有React支持的原生事件)
allNativeEvents.forEach(domEventName => {
if (domEventName !== 'selectionchange') {
//1. 双阶段监听 对每个事件同时注册:
//冒泡阶段(capture=false)
if (!nonDelegatedEvents.has(domEventName)) {
//通过 nonDelegatedEvents 集合过滤无法冒泡的事件(如load/reset等)
listenToNativeEvent(domEventName, false, rootContainerElement);
}
// 捕获阶段(capture=true)
listenToNativeEvent(domEventName, true, rootContainerElement);
}
});
//判断非selectionchange事件
const ownerDocument =
(rootContainerElement: any).nodeType === DOCUMENT_NODE
? rootContainerElement
: (rootContainerElement: any).ownerDocument;
if (ownerDocument !== null) {
if (!(ownerDocument: any)[listeningMarker]) {
(ownerDocument: any)[listeningMarker] = true;
listenToNativeEvent('selectionchange', false, ownerDocument);
}
}
}
//桥接函数
function listenToNativeEvent(
domEventName: DOMEventName,
isCapturePhaseListener: boolean,
target: EventTarget,
): void {
let eventSystemFlags = 0;
//定义是否冒泡
if (isCapturePhaseListener) {
eventSystemFlags |= IS_CAPTURE_PHASE;
}
//监听
addTrappedEventListener(
target,
domEventName,
eventSystemFlags,
isCapturePhaseListener,
);
}
function addTrappedEventListener(
targetContainer: EventTarget,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
isCapturePhaseListener: boolean,
isDeferredListenerForLegacyFBSupport?: boolean,
) {
// 核心逻辑分为四个阶段:
// 1. 创建带优先级的事件监听器包装函数
let listener = createEventListenerWrapperWithPriority(
targetContainer,
domEventName,
eventSystemFlags,
);
// 2. 处理被动事件优化(针对 touch/wheel 等特定事件)
let isPassiveListener = undefined;
if (passiveBrowserEventsSupported) {
if (domEventName === 'touchstart' || ... ) {
isPassiveListener = true;
}
}
// 3. 处理遗留的 Facebook 支持模式
if (enableLegacyFBSupport && ... ) {
// 创建自动移除的一次性监听器
listener = function(...p) {
removeEventListener(...);
return originalListener(...);
};
}
// 4. 最终绑定事件监听器
if (isCapturePhaseListener) {
// 捕获阶段监听逻辑
unsubscribeListener = addEventCaptureListenerWithPassiveFlag(...);
} else {
// 冒泡阶段监听逻辑
unsubscribeListener = addEventBubbleListenerWithPassiveFlag(...);
}
}
function addEventCaptureListenerWithPassiveFlag(
target: EventTarget,
eventType: string,
listener: Function,
passive: boolean,
): Function {
//最终事件绑定
target.addEventListener(eventType, listener, {
capture: true,
passive,
});
return listener;
}
addTrappedEventListener函数在 React 事件系统中的核心作用:
- 事件优先级分层 通过 createEventListenerWrapperWithPriority 实现三级优先级:
- DiscreteEvent(离散事件:click/keydown 等)
- UserBlockingEvent(用户阻塞事件:mouseover 等)
- ContinuousEvent(持续事件:load/error 等)
export function createEventListenerWrapperWithPriority(
targetContainer: EventTarget,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
): Function {
const eventPriority = getEventPriority(domEventName);
let listenerWrapper;
switch (eventPriority) {
case DiscreteEventPriority:
// 离散事件, 例如 click, change, submit 等
listenerWrapper = dispatchDiscreteEvent;
break;
case ContinuousEventPriority:
// 连续事件, 例如 mousemove, scroll 等
listenerWrapper = dispatchContinuousEvent;
break;
case DefaultEventPriority:
default:
// 默认事件, 例如 load, error 等
listenerWrapper = dispatchEvent;
break;
}
return listenerWrapper.bind(
null,
domEventName,
eventSystemFlags,
targetContainer,
);
}
- 被动事件优化 对 touchstart / touchmove / wheel 等影响滚动的关键事件:
// 强制设置为 passive:true 来优化滚动性能
isPassiveListener = true;
- 特殊事件处理 通过
eventSystemFlags参数实现特殊事件标记:
// 事件系统标记示例
const IS_CAPTURE_PHASE = 0b0001; // 捕获阶段
const IS_PASSIVE = 0b0010; // 被动模式
const IS_LEGACY_MODE = 0b0100; // 传统支持模式
最终通过addEventListener来对各种事件进行绑定
回顾下,create阶段就是创建了系统根节点FiberRootNode,并且与根节点RootFiber通过current进行了绑定
通过事件优先级,将具体的元素事件都绑定到了根节点上
至此,我们完成了创建Rootfiber和fiberRoot,初始化了更新队列,完成了浏览器事件托管监听,接下来调用render进入协调阶段
render阶段
18版本后render
new ReactDOMRoot(root)实例后,重写了ReactDOMRoot.prototype.render 方法
render调用 updateContainer方法,自动更新container
ReactDOMRoot.prototype.render = function(
children: ReactNodeList,
): void {
const root = this._internalRoot;
updateContainer(children, root, null, null);
};
和老版本的ReactDom.render是一样,本质上都是调用updateContainer,只不过我们18版本后提前createApp创建了根节点
18版本前 ReactDom.render入口
实际调用legacyRenderSubtreeIntoContainer,默认开启异步渲染
function render(element: React$Element<any>, container: DOMContainer, callback?: ?Function) {
return legacyRenderSubtreeIntoContainer(
null, //父组件,首次渲染时为 null, 表示没有父组件
element, // 要渲染的元素
container, // 容器
false, // 是否同步渲染,false 表示异步渲染
callback, // 渲染完成后的回调函数
);
}
1.legacyRenderSubtreeIntoContainer
负责将具体的组件子树渲染到指定的DOM容器中,此一次启动应用_reactRootContainer为null,默认创建一个新的root
function legacyRenderSubtreeIntoContainer(
parentComponent: ?React$Component<any, any>,
children: ReactNodeList,
container: DOMContainer,
forceHydrate: boolean,
callback: ?Function,
) {
// 1. 找到根节点
const maybeRoot = container._reactRootContainer;
let root: FiberRoot;
if (!maybeRoot) {
// 2. 没有根节点,创建一个新的根节点
root = legacyCreateRootFromDOMContainer(
container,
forceHydrate,
);
}else {
// 3. 有根节点,直接使用
root = maybeRoot;
// 更新容器
// 进入reconciler 协调器 阶段
updateContainer(children, root, parentComponent, callback);
}
//获取 Fiber 树的公共根实例
//作为 React 内部与外部(如 ReactDOM)的桥梁
return getPublicRootInstance(root);
}
2.legacyCreateRootFromDOMContainer
用来将一个已有的DOM元素转换为一个React的根节点
function legacyCreateRootFromDOMContainer(
container: DOMContainer,
isHydrationContainer: boolean,
) {
if(isHydrationContainer){
// 是否是 hydration 容器
// 创建一个水合容器
// 可以在服务端渲染(SSR)中使用,用于将服务端渲染的 HTML 与 React 组件进行合并,生成最终的 HTML
// 例如next.js框架
const root = createHydrationContainer(container);
container._reactRootContainer = root;
markContainerAsRoot(root.current, container);
const rootContainerElement =
container.nodeType === COMMENT_NODE ? container.parentNode : container;
listenToAllSupportedEvents(rootContainerElement);
flushSync();
return root;
}else{
// 2. 不是 hydration 容器,创建一个新容器
// createFiberRoot
const root = createContainer(container);
//添加_reactRootContainer
container._reactRootContainer = root;
//标记__reactContainer
markContainerAsRoot(root.current, container);
//判断容器类型 注释容器-〉使用其父节点作为根容器 负责 直接使用原容器
const rootContainerElement =
container.nodeType === COMMENT_NODE ? container.parentNode : container;
//在此真实DOM节点上绑定所有支持的事件
listenToAllSupportedEvents(rootContainerElement);
// 初始挂载不应批量处理
flushSync(() => {
//更新容器
updateContainer(initialChildren, root, parentComponent, callback);
});
return root;
}
}
3.flushSync
flushSync是 React 调度系统中的关键同步刷新机制,主要功能是强制同步执行更新
export function flushSync(fn) {
// 保存原始执行上下文
const prevExecutionContext = executionContext;
//上下文切换 :通过 BatchedContext 标志进入批量更新模式
executionContext |= BatchedContext;
try {
if (fn) {
// 同步执行回调函数
return syncUpdates(() => {
return fn();
});
} else {
return undefined
}
} finally {
// 恢复执行上下文
executionContext = prevExecutionContext;
if ((executionContext & (RenderContext | CommitContext)) === NoContext) {
//立即处理所有同步回调 确保在浏览器绘制前完成关键状态更新
flushSyncCallbacks();
}
}
}
flushSync → flushSyncCallbacks → 执行同步回调 → 触发同步渲染
后面我们具体讲updateContainer