react三种启动模式
- legacy
// LegacyRoot
ReactDOM.render(<App />, document.getElementById('root'), dom => {}); // 支持callback回调, 参数是一个dom对象
- Blocking模式
仅提供了 concurrent 模式的小部分功能, 作为迁移到 concurrent 模式的第一个步骤.
// BolckingRoot
// 1. 创建ReactDOMRoot对象
const reactDOMBolckingRoot = ReactDOM.createBlockingRoot(
document.getElementById('root'),
);
// 2. 调用render
reactDOMBolckingRoot.render(<App />); // 不支持回调
- Concurrent模式
这个模式开启了所有的新功能
// ConcurrentRoot
// 1. 创建ReactDOMRoot对象
const reactDOMRoot = ReactDOM.createRoot(document.getElementById('root'));
// 2. 调用render
reactDOMRoot.render(<App />); // 不支持回调
legacy启动
- ReactDOM.render后续调用legacyRenderSubtreeIntoContainer
legacyRenderSubtreeIntoContainer
function legacyRenderSubtreeIntoContainer(
parentComponent: ?React$Component<any, any>,
children: ReactNodeList,
container: Container,
forceHydrate: boolean,
callback: ?Function,
) {
let root: RootType = (container._reactRootContainer: any);
let fiberRoot;
if (!root) {
// 初次调用, root还未初始化, 会进入此分支
//1. 创建ReactDOMRoot对象, 初始化react应用环境
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
container,
forceHydrate,
);
//获取fiberRoot
fiberRoot = root._internalRoot;
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function() {
// instance最终指向children生成的dom节点(入参: 如<App/>)
const instance = getPublicRootInstance(fiberRoot);
originalCallback.call(instance);
};
}
// 2. 调用unbatchedUpdates更新容器
unbatchedUpdates(() => {
updateContainer(children, fiberRoot, parentComponent, callback);
});
// root已经初始化, 二次调用render会进入
} else {
// 1. 获取ReactDOMRoot对象
fiberRoot = root._internalRoot;
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function() {
const instance = getPublicRootInstance(fiberRoot);
originalCallback.call(instance);
};
}
// 2. 调用更新
updateContainer(children, fiberRoot, parentComponent, callback);
}
return getPublicRootInstance(fiberRoot);
}
legacyCreateRootFromDOMContainer
function legacyCreateRootFromDOMContainer(
container: Container,
forceHydrate: boolean,
): RootType {
const shouldHydrate =
forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
//实际调用createLegacyRoot
return createLegacyRoot(
container,
shouldHydrate
? {
hydrate: true,
}
: undefined,
);
}
export function createLegacyRoot(
container: Container,
options?: RootOptions,
): RootType {
return new ReactDOMBlockingRoot(container, LegacyRoot, options); // 注意这里的LegacyRoot是固定的, 并不是外界传入的
}
- 创建ReactDOMBlockingRoot实例(在 Concurrent 模式和 Blocking 模式中也是), 初始化 react 应用环境
- 然后后续调用updateContainer进行更新.
Concurrent 模式和 Blocking 模式
- 分别调用ReactDOM.createRoot和ReactDOM.createBlockingRoot创建ReactDOMRoot和ReactDOMBlockingRoot实例
- 然后调用ReactDOMRoot和ReactDOMBlockingRoot实例的render方法
export function createRoot(
container: Container,
options?: RootOptions,
): RootType {
return new ReactDOMRoot(container, options);
}
export function createBlockingRoot(
container: Container,
options?: RootOptions,
): RootType {
return new ReactDOMBlockingRoot(container, BlockingRoot, options); // 注意第2个参数BlockingRoot是固定写死的
}
ReactDOMRoot和ReactDOMBlockingRoot对象
function ReactDOMRoot(container: Container, options: void | RootOptions) {
// 创建一个fiberRoot对象, 并将其挂载到this._internalRoot之上
this._internalRoot = createRootImpl(container, ConcurrentRoot, options);
}
//也是legacy模式最后返回的实例
function ReactDOMBlockingRoot(
container: Container,
tag: RootTag,
options: void | RootOptions,
) {
// 创建一个fiberRoot对象, 并将其挂载到this._internalRoot之上
this._internalRoot = createRootImpl(container, tag, options);
}
ReactDOMRoot.prototype.render = ReactDOMBlockingRoot.prototype.render = function(
children: ReactNodeList,
): void {
const root = this._internalRoot;
// 执行更新
updateContainer(children, root, null, null);
};
ReactDOMRoot.prototype.unmount = ReactDOMBlockingRoot.prototype.unmount = function(): void {
const root = this._internalRoot;
const container = root.containerInfo;
// 执行卸载更新
updateContainer(null, root, null, () => {
unmarkContainerAsRoot(container);
});
};
createRootImpl
function createRootImpl(
container: Container,
tag: RootTag,
options: void | RootOptions,
) {
// ... 省略部分源码(有关hydrate服务端渲染等, 暂时用不上)
// 1. 创建fiberRoot
const root = createContainer(container, tag, hydrate, hydrationCallbacks); // 注意RootTag的传递
// 2. 标记dom对象, 把dom和fiber对象关联起来
markContainerAsRoot(root.current, container);
// ...省略部分无关代码
return root;
}
createContainer
export function createContainer(
containerInfo: Container,
tag: RootTag,
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
): OpaqueRoot {
// 创建fiberRoot对象
return createFiberRoot(containerInfo, tag, hydrate, hydrationCallbacks); // 注意RootTag的传递
}
createFiberRoot
- 创建fiberRoot
- 创建RootFiber,且fiber.tag = HostRootFiber
export function createFiberRoot(
containerInfo: any,
tag: RootTag,
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
): FiberRoot {
// 创建fiberRoot对象, 注意RootTag的传递
const root: FiberRoot = (new FiberRootNode(containerInfo, tag, hydrate): any);
// 1. 这里创建了`react`应用的首个`fiber`对象, 称为`HostRootFiber`
const uninitializedFiber = createHostRootFiber(tag);
// fiberRoot的current指向了rootFiber
root.current = uninitializedFiber;
//rootFiber的stateNode保存root实例
uninitializedFiber.stateNode = root;
// 2. 初始化HostRootFiber的updateQueue
initializeUpdateQueue(uninitializedFiber);
return root;
}
createHostRootFiber
- 其中fiber.mode属性, 会与 3 种RootTag(ConcurrentRoot,BlockingRoot,LegacyRoot)关联起来
- fiber树中节点的mode都会和HostRootFiber.mode一致(新建的 fiber 节点, 其 mode 来源于父节点)
- mode决定了以后整个 fiber 树构建过程
export function createHostRootFiber(tag: RootTag): Fiber {
let mode;
if (tag === ConcurrentRoot) {
mode = ConcurrentMode | BlockingMode | StrictMode;
} else if (tag === BlockingRoot) {
mode = BlockingMode | StrictMode;
} else {
mode = NoMode;
}
return createFiber(HostRoot, null, null, mode); // 注意这里设置的mode属性是由RootTag决定的
}
legacy模式下
concurrent模式下
blocking模式下
调用更新
legacy中
unbatchedUpdates(() => {
updateContainer(children, fiberRoot, parentComponent, callback);
});
concurrent和blocking中
ReactDOMRoot.prototype.render = ReactDOMBlockingRoot.prototype.render = function(
children: ReactNodeList,
): void {
const root = this._internalRoot;
// 执行更新
updateContainer(children, root, null, null);
};
updateContainer
export function updateContainer(
element: ReactNodeList,
container: OpaqueRoot,//fiberRoot
parentComponent: ?React$Component<any, any>,
callback: ?Function,
): Lane {
//即fiberRoot.current,指向了rootFiber
const current = container.current;
// 1. 获取当前时间戳, 计算本次更新的优先级
const eventTime = requestEventTime();
const lane = requestUpdateLane(current);
// 2. 设置fiber.updateQueue
const update = createUpdate(eventTime, lane);
update.payload = { element };
callback = callback === undefined ? null : callback;
if (callback !== null) {
update.callback = callback;
}
enqueueUpdate(current, update);
// 3. 进入reconcier运作流程中的`输入`环节,即通过scheduler注册调度任务
scheduleUpdateOnFiber(current, lane, eventTime);
return lane;
}
- 需要关注最后调用了scheduleUpdateOnFiber,进入了scheduler阶段
最终
- 启动过程最后调用updateContainer进入react-reconciler包,进而调用schedulerUpdateOnFiber函数