React 初始化的函数函数为ReactDom.render(), 进行更新有三种方式 ReactDom.render(), setState, forceUpdate 等。
// render 定义(1)
// ReactDom 执行render 的方法
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMLegacy.js
// 目的: 调用legacyRenderSubtreeIntoContainer 函数
export function render(
element: React$Element<any>, // ReactElement 元素
container: Container, // 容器
callback: ?Function, // 回调函数
) {
// 执行 legacyRenderSubtreeIntoContainer 方法
return legacyRenderSubtreeIntoContainer(
null,
element,
container,
false,
callback,
);
}
备注: React 入口函数, 传入的参数为element, 和container 等信息, 回调函数一般不传入, 传入后会执行。
// legacyRenderSubtreeIntoContainer 函数定义(2)
// 定义 legacyRenderSubtreeIntoContainer 方法
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMLegacy.js
// 主体逻辑: 根据container.root 有无,判断是否为初始后或更新,无: 执行生成fiberRoot, 再执行非批量
// 更新 ,有: 执行普通的更新
function legacyRenderSubtreeIntoContainer(
parentComponent: ?React$Component<any, any>, // 初始为null
children: ReactNodeList,
container: Container,
forceHydrate: boolean, // false
callback: ?Function,
) {
// TODO: Without `any` type, Flow says "Property cannot be accessed on any
// member of intersection type." Whyyyyyy.
// 初始化, 无属性,
let root: RootType = (container._reactRootContainer: any);
let fiberRoot;
// 初始化
if (!root) {
// Initial mount
// 获取_reactRootContainer 属性
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
container,
forceHydrate, // false
);
// 定义fiberRoot
fiberRoot = root._internalRoot;
if (typeof callback === 'function') { // 回调函数
const originalCallback = callback;
callback = function() {
// 实例
const instance = getPublicRootInstance(fiberRoot);
originalCallback.call(instance); // 最原始回调函数
};
}
// Initial mount should not be batched.
// 非批量更新的方式
unbatchedUpdates(() => { // 设置执行环境
// 更新的节点, fiberRoot, parentComponent 父节点 callback : 回调
updateContainer(children, fiberRoot, parentComponent, callback);
});
} else {
// 当具有root 时候, 更新的时候
fiberRoot = root._internalRoot; // fiberRoot
if (typeof callback === 'function') { // 具有回调函数
const originalCallback = callback;
callback = function() { // 包裹回调函数
// 实例
const instance = getPublicRootInstance(fiberRoot);
originalCallback.call(instance); // 回调函数调用
};
}
// Update // 进行更新, 非批量更新
updateContainer(children, fiberRoot, parentComponent, callback); // null 回调
}
return getPublicRootInstance(fiberRoot);
}
备注: 通过container._reactRootContainer 构建基本的信息,基本的结构信息包含fiberRoot 和rootFiber, 应用更新的初始化和更新都是从fiberRoot开始。对回调函数进行包裹处理, 最后在unbatchedUpdates 执行回调函数, 初始化时,想最快速度展示页面,从而是非批量同步更新。 root 存在时, 也可以进行更新,连续调用React.ReactDom, 会走存在的路线。
// 定义legacyCreateRootFromDOMContainer 方法(3)
// 定义legacyCreateRootFromDOMContainer 方法,
// 获取root // container._reactRootContainer
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMLegacy.js
/// 主题逻辑: 是否需要hydrate条件生成, 调用createLegacyRoot
function legacyCreateRootFromDOMContainer(
container: Container, // container
forceHydrate: boolean, // false
): RootType {
// 是否需要hydrate 的判断, 可以忽略部分, 现在只考察shouldHydrate 为false 的情况
const shouldHydrate =
forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
// First clear any existing content.
if (!shouldHydrate) {
let warned = false;
let rootSibling;
// 清空原来container 中所有子元素
while ((rootSibling = container.lastChild)) {
container.removeChild(rootSibling);
}
}
return createLegacyRoot(
container,
shouldHydrate
? {
hydrate: true,
}
: undefined,
);
}
// 定义shouldHydrateDueToLegacyHeuristic 方法(4)
// 函数shouldHydrateDueToLegacyHeuristic 定义
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMLegacy.js
// 主体逻辑: 获取rootElement 元素, 并 进行判断
function shouldHydrateDueToLegacyHeuristic(container) {
const rootElement = getReactRootElementInContainer(container);
return !!(
rootElement &&
rootElement.nodeType === ELEMENT_NODE &&
rootElement.hasAttribute(ROOT_ATTRIBUTE_NAME)
);
}
// 定义getReactRootElementInContainer 方法(5)
// getReactRootElementInContainer 定义
代码位置: src/react/packages/react-dom/src/client/ReactDOMLegacy.js
主题逻辑 : 先判断存在,在判断是否为document, 最后返回第一个元素
function getReactRootElementInContainer(container: any) {
if (!container) {
return null;
}
// 是否为document
if (container.nodeType === DOCUMENT_NODE) {
return container.documentElement;
} else {
// 第一个子节点
return container.firstChild;
}
}
// 定义 createLegacyRoot 方法(6)
// 调用 createLegacyRoot 方法
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMRoot.js
// 主题逻辑: // 传入LegacyRoot 参数, 调用构造函数, 返回值为container._reactRootContainer 对应的值
export function createLegacyRoot(
container: Container,
options?: RootOptions,
): RootType {
// LegacyRoot 遗留类型的root options : null
// new ReactDOMBlockingRoot() 实例 对应root 即 container.reactRootContainer
return new ReactDOMBlockingRoot(container, LegacyRoot, options); // LegacyRoot
}
//备注: src/react/packages/react-reconciler/src/ReactRootTags.js
export type RootTag = 0 | 1 | 2;
export const LegacyRoot = 0; // 即遗留的root
export const BlockingRoot = 1; // 阻塞的root类型
export const ConcurrentRoot = 2; // concurrentRoot
// 构造函数ReactDOMBlockingRoot 定义(7)
// ReactDOMBlockingRoot 构造函数的定义
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMRoot.js
// 主题逻辑; 在原实例上,增加属性, _internalRoot 对应fiberRoot
function ReactDOMBlockingRoot(
container: Container,
tag: RootTag, // rootTag的类型
options: void | RootOptions,
) {
// root / contain._reactRootContainer 的结果就是 ReactDOMBlockingRoot 实例
// this._internalRoot 对应fiberRoot 属性
this._internalRoot = createRootImpl(container, tag, options); //
// container 容器, tag 类型 options 参数
}
// 函数createRootImpl 定义(8)
// 定义 createRootImpl 函数
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMRoot.js
// 主题逻辑: 1 fiberRoot的构造, 2 fiberRoot 和container关系, 3, 基本事件的挂载
// tag : 0 , options: undefined // root 对应fiberRoot
function createRootImpl(
container: Container, // 容器类型
tag: RootTag, // rootTag 的类型
options: void | RootOptions,
) {
// Tag is either LegacyRoot or Concurrent Root
// 服务端渲染的参数
const hydrate = options != null && options.hydrate === true;
// 服务端渲染的回调参数
const hydrationCallbacks =(options != null && options.hydrationOptions) || null;
const mutableSources =(options != null &&options.hydrationOptions != null && options.hydrationOptions.mutableSources) ||
null;
// 定义root 属性
// container 容器 tag: 0 hydrate : false, hydrationCallbacks : null
// root 对应为fiberRoot
const root = createContainer(container, tag, hydrate, hydrationCallbacks);
markContainerAsRoot(root.current, container); //
// 设置container 与root.current 的关系
const containerNodeType = container.nodeType;
// enableEagerRootListeners // true; 是否支持挂载到元素上
// true
if (enableEagerRootListeners) {
// 根容器的节点, react 17 中的事件挂载
const rootContainerElement =
container.nodeType === COMMENT_NODE ? container.parentNode : container;
listenToAllSupportedEvents(rootContainerElement); // 挂载的节点
} else {
// 其他方式
if (hydrate && tag !== LegacyRoot) {
const doc =
containerNodeType === DOCUMENT_NODE
? container
: container.ownerDocument;
// We need to cast this because Flow doesn't work
// with the hoisted containerNodeType. If we inline
// it, then Flow doesn't complain. We intentionally
// hoist it to reduce code-size.
eagerlyTrapReplayableEvents(container, ((doc: any): Document));
} else if (
containerNodeType !== DOCUMENT_FRAGMENT_NODE &&
containerNodeType !== DOCUMENT_NODE
) {
ensureListeningTo(container, 'onMouseEnter', null);
}
}
// 服务端的参数
if (mutableSources) {
for (let i = 0; i < mutableSources.length; i++) {
const mutableSource = mutableSources[i];
registerMutableSourceForHydration(root, mutableSource);
}
}
// root 的返回
return root; // root 对应为fiberRoot 对象
}
// 函数createContainer 定义(9)
// 创建FiberRoot的方法
// 代码位置: src/react/packages/react-reconciler/src/ReactFiberReconciler.old.js
// 主体逻辑: 调用createFiberRoot 函数
// containerInfo: container tag: 0, // hydrate : false, hydrationCallbacks: null
export function createContainer(
containerInfo: Container,
tag: RootTag, // rootTag 的类型
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
): OpaqueRoot {
return createFiberRoot(containerInfo, tag, hydrate, hydrationCallbacks);
}
// 函数createFiberRoot 定义(10)
// 创建FiberRoot的节点
// 代码位置: src/react/packages/react-reconciler/src/ReactFiberRoot.old.js
// 主题逻辑: 1 创建fiberRoot 和rootFiber, 设立两者关系, 初始化rootFiber 中updateQueue
export function createFiberRoot(
containerInfo: any,
tag: RootTag, // rootTag的类型
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
): FiberRoot {
// 创建FiberRoot 节点 containerInfo 容器的信息 tag:rooTag的信息
const root: FiberRoot = (new FiberRootNode(containerInfo, tag, hydrate): any);
//
if (enableSuspenseCallback) {
root.hydrationCallbacks = hydrationCallbacks;
}
// Cyclic construction. This cheats the type system right now because
// stateNode is any.
// 获取rootFiber
const uninitializedFiber = createHostRootFiber(tag); // 初始化rootFiber
root.current = uninitializedFiber; // FiberRoot 的current 执行rootFiber
uninitializedFiber.stateNode = root;
// rootFiber.stateNode 指向fiberRoot
initializeUpdateQueue(uninitializedFiber); // rootFiber
return root;
}
// FiberRootNode 构造函数定义(11)
// FiberRootNode 构造函数定义 // containerInfo 容器 tag: 0 hydrate: false
// 代码位置: src/react/packages/react-reconciler/src/ReactFiberRoot.old.js
// 主题逻辑: 根据tag 创建fiberRoot
function FiberRootNode(containerInfo, tag, hydrate) {
// fiberRoot 对象,1: 整个应用的起点, 2, 包含应用挂载的目标节点
// 3 记录整个应用的更新过程的全部信息
// containerInfo 容器 tag rootTag 类型 hydrate
this.tag = tag; // tag: 0 // rootTag 类型
// react的各种模式
// NoMode = 0b00000;
// StrictMode = 0b00001;
// BlockingMode = 0b00010;
// ConcurrentMode = 0b00100;
// ProfileMode = 0b01000;
// root节点,render方法接收的第二个参数
this.containerInfo = containerInfo; // 容器信息
// 只有在持久更新中会用到,也就是不支持增量更新的平台,react-dom不会用到
this.pendingChildren = null; // 持久化更新的信息
// 当前应用对应的Fiber对象,是Root Fiber
this.current = null; // root节点对应fiber 节点
this.pingCache = null;
// The earliest and latest priority levels that are suspended from committing.
// 最老和新的在提交的时候被挂起的任务
// 已经完成的任务的FiberRoot对象,如果你只有一个Root,那他永远只可能是这个Root对应的Fiber,或者是null
// 在commit阶段只会处理这个值对应的任务
this.finishedWork = null;
// 在任务被挂起的时候,通过setTimeout设置的返回的内容
// 用来下一次如果有新的任务挂起时, 清除没有触发的timeout
// 在任务被挂起的时候通过setTimeout设置的返回内容,用来下一次如果有新的任务挂起时清理还没触发的timeout
this.timeoutHandle = noTimeout; // -1
// 顶层的context 对象, 只有主动调用renderSubtreeIntoContainer 的时候才会用
// 顶层context对象,只有主动调用`renderSubtreeIntoContainer`时才会有用
this.context = null;
this.pendingContext = null;
this.hydrate = hydrate;
this.callbackNode = null;
this.callbackPriority = NoLanePriority; //
this.eventTimes = createLaneMap(NoLanes); // 31位的空的数组, 中间的值位 NoLanes: 0b0000000000000000000000000000000;
this.expirationTimes = createLaneMap(NoTimestamp); // 过期时间 -1
this.pendingLanes = NoLanes; // 0b0000000000000000000000000000000;
this.suspendedLanes = NoLanes; // 0b0000000000000000000000000000000;
this.pingedLanes = NoLanes; // 0b0000000000000000000000000000000;
this.expiredLanes = NoLanes; // 过期的 0b0000000000000000000000000000000;
this.mutableReadLanes = NoLanes; // 0b0000000000000000000000000000000;
this.finishedLanes = NoLanes; // 完成的 0b0000000000000000000000000000000;
this.entangledLanes = NoLanes; // 0b0000000000000000000000000000000;
this.entanglements = createLaneMap(NoLanes); // 0b0000000000000000000000000000000;
// 支持Hrate
if (supportsHydration) {
this.mutableSourceEagerHydrationData = null;
}
// 能够调度追踪,
if (enableSchedulerTracing) {
this.interactionThreadID = unstable_getThreadID();
this.memoizedInteractions = new Set();
this.pendingInteractionMap = new Map();
}
if (enableSuspenseCallback) {
this.hydrationCallbacks = null;
}
}
// createLaneMap 定义(12)
// 创建一个LaneMAp
// 代码位置: src/react/packages/react-reconciler/src/ReactFiberLane.js
// 主题逻辑: 创建一个包含31个元素的数组, 值为传入的参数
export function createLaneMap<T>(initial: T): LaneMap<T> {
// Intentionally pushing one by one.
// https://v8.dev/blog/elements-kinds#avoid-creating-holes
// 空数组
const laneMap = [];
// 31
for (let i = 0; i < TotalLanes; i++) {
laneMap.push(initial);
}
return laneMap; // []
}
// createHostRootFiber 函数定义(13)
// 创建HostRootFiber 节点 tag : 0
代码位置: src/react/packages/react-reconciler/src/ReactFiber.old.js
主题逻辑: 根据传入的tag 确定mode , 调用创建rootFiber
export function createHostRootFiber(tag: RootTag): Fiber {
// 模式定义
let mode;
// 当模式为ConcurrentMode m模式下
if (tag === ConcurrentRoot) {
// mode 增加严格, concurrent
mode = ConcurrentMode | BlockingMode | StrictMode;
// ConcurrentMode 模式 BlockingMode : 模式 StrictMode: 模式
} else if (tag === BlockingRoot) {
// Blocak //
mode = BlockingMode | StrictMode;// BlockingMode 模式, StrictMode 模式
} else {
// 没有模式
mode = NoMode;
}
if (enableProfilerTimer && isDevToolsPresent) {
mode |= ProfileMode;
}
// 创建Fiber // 匹配模式
return createFiber(HostRoot, null, null, mode);
// HostRoot
}
// createFiber 函数定义 (14)
// 创建Fiber 节点的函数 // 创建HostRootFiber 节点
// 代码位置: src/react/packages/react-reconciler/src/ReactFiber.old.js
// 主题逻辑: 调用构造函数返回rootFiber, tag 为3, 表示root 节点
// pendingProps : null , key: null, tag: HostRoot
const createFiber = function(
tag: WorkTag,
pendingProps: mixed, // {}
key: null | string, //
mode: TypeOfMode,
): Fiber {
// $FlowFixMe: the shapes are exact here but Flow doesn't like constructors
// 创建的FiberNode节点
return new FiberNode(tag, pendingProps, key, mode);
};
// FiberNode 构造函数 (15)
// FiberNode 的构造函数
// 代码位置: src/react/packages/react-reconciler/src/ReactFiber.old.js
// 主体逻辑: 定义了构造函数
function FiberNode(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
// Instance
// 标记不同的组件类型
this.tag = tag; // 类型
// ReactElement里面的key
this.key = key; // key
// ReactElement.type,也就是我们调用`createElement`的第一个参数
this.elementType = null;
// The resolved function/class/ associated with this fiber.
// 异步组件resolved之后返回的内容,一般是`function`或者`class`
this.type = null; // 类型
// The local state associated with this fiber.
// 跟当前Fiber相关本地状态(比如浏览器环境就是DOM节点)
this.stateNode = null; // dom 节点 // dom 实例或者class 实例
// Fiber
// 指向他在Fiber节点树中的`parent`,用来在处理完这个节点之后向上返回
this.return = null; // 返回的结构
// 单链表树结构
// 指向自己的第一个子节点
this.child = null; // 子节点
// 指向自己的兄弟结构
// 兄弟节点的return指向同一个父节点
this.sibling = null; // 兄弟节点
this.index = 0; // 下标, 记录位置
// ref属性
this.ref = null; // ref , 最后使用de shui
// 新的变动带来的新的props
this.pendingProps = pendingProps; // 待更新props
// 上一次渲染完成之后的props
this.memoizedProps = null; // 已经更新的props
// 该Fiber对应的组件产生的Update会存放在这个队列里面
this.updateQueue = null; // 更新队列
// 上一次渲染的时候的state
this.memoizedState = null; // 更新的队列
this.dependencies = null; // 同fiber 相关的context 事件
// 处于什么模式 concurerntMode 或者其他模式
// 用来描述当前Fiber和他子树的`Bitfield`
// 共存的模式表示这个子树是否默认是异步渲染的
// Fiber被创建的时候他会继承父Fiber
// 其他的标识也可以在创建的时候被设置
// 但是在创建之后不应该再被修改,特别是他的子Fiber创建之前
this.mode = mode; // 受父节点控制
// Effects
// Effect
// 用来记录Side Effect
this.flags = NoFlags; // 副作用标示 PLACEMENT UPDATE , DELETE
// 单链表用来快速查找下一个side effect
this.nextEffect = null;
// 子树中第一个side effect
this.firstEffect = null;
// 子树中最后一个side effect
this.lastEffect = null;
// 代表任务在未来的哪个时间点应该被完成
// 不包括他的子树产生的任务
this.lanes = NoLanes; // 过期事件, 二进制位
// 快速确定子树中是否有不在等待的变化
this.childLanes = NoLanes; // 子节点的
// 在Fiber树更新的过程中,每个Fiber都会有一个跟其对应的Fiber
// 我们称他为`current <==> workInProgress`
// 在渲染完成之后他们会交换位置
this.alternate = null; // 指向旧的fiber
// profiler 组件,计算react 的时间
if (enableProfilerTimer) {
this.actualDuration = Number.NaN;
this.actualStartTime = Number.NaN;
this.selfBaseDuration = Number.NaN;
this.treeBaseDuration = Number.NaN;
this.actualStartTime = -1;
this.selfBaseDuration = 0;
this.treeBaseDuration = 0;
}
}
// initializeUpdateQueue 定义(16)
// 初始化更新队列 fiber: uninitlialFiber rootFiber
// 代码位置: src/react/packages/react-reconciler/src/ReactUpdateQueue.old.js
// 主题逻辑: 给rootFiber 中的updateQueue 增加一个初始的queue
export function initializeUpdateQueue<State>(fiber: Fiber): void {
// 设置更新队列
// 设置更新队列
const queue: UpdateQueue<State> = {
baseState: fiber.memoizedState, // 原来的更新的基础
// 记录数据结构, 开始
firstBaseUpdate: null, // 最开始BasUpdate
// 记录数据结构, 结束
lastBaseUpdate: null,
shared: {
pending: null,
},
effects: null, // 当前update 的副作用
};
// 更新队列
// rootFiber 中的updateQueue ,设置一个初始值
fiber.updateQueue = queue; // rootFiber 的updateQueue 设置更新
// 给uninitlialFiber
// 设置rootFiber的更新队列
}
// markContainerAsRoot 定义(17)
// hostRoot fiberRoot.current node: container
/// 定义markContainerAsRoot
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMComponentTree.js
// 主题逻辑: 设置container.internalContainerInstanceKey 指向rootFiber
export function markContainerAsRoot(hostRoot: Fiber, node: Container): void {
// container. internalContainerInstanceKey = fiberRoot.current
// 设置指向
node[internalContainerInstanceKey] = hostRoot;
}
// 备注信息:
const randomKey = Math.random()
.toString(36)
.slice(2);
const internalContainerInstanceKey = '__reactContainer$' + randomKey;
// listenToAllSupportedEvents 定义(18)
// 当enableEagerRootListeners 对container 的元素的绑定
// rootContainerElement: container
// 代码位置: src/react/packages/react-dom/src/events/DOMPluginEventSystem.js
// 主题逻辑: 将触发的事件绑定的container , 冒泡阶段和触发分别绑定
export function listenToAllSupportedEvents(rootContainerElement: EventTarget) {
// ture
if (enableEagerRootListeners) {
// 初始为undefined
if ((rootContainerElement: any)[listeningMarker]) {
return;
}
// 初始false
(rootContainerElement: any)[listeningMarker] = true;
// 各种事件类型
allNativeEvents.forEach(domEventName => {
// 不进行冒泡代理的事件和 必须要绑定在指定元素的事件
if (!nonDelegatedEvents.has(domEventName)) {
// 冒泡阶段的事件代理
listenToNativeEvent(
domEventName, // 事件类型
false,
((rootContainerElement: any): Element),
null,
);
}
// 在触发阶段的绑定
listenToNativeEvent(
domEventName,
true,
((rootContainerElement: any): Element),
null,
);
});
}
}
// 备注
export const deferRenderPhaseUpdateToNextBatch = true;
流程图
总结信息:
1 通过ReactDom.render() 进行初始化流程, 再次更新的时候也可以通过ReactDom.render() 进行更新。
2 container.reactRootContainer 为一个ReactDOMBlockingRoot实例。实例的_internalRoot 为fiberRoot ,
3 创建rootFiber 对象, 设置rootFiber 与container 的关系,在游览器下设置部分事件挂载在container.
4 初始化queue 添加到rootFiber 的updateQueue上。