ReactDOM.render 做了什么?
ReactDOM.render
以下代码是render方法的实现, render方法其实接受三个参数, callback平时用的较少
typescript
render(
element: React$Element<any>,
container: DOMContainer,
callback: ?Function,
) {
return legacyRenderSubtreeIntoContainer(
null,
element,
container,
false,
callback,
);
}创建ReactRoot
首先,render方法执行的时候,调用legacyRenderSubtreeIntoContainer 方法创建ReactRoot对象
typescript
function legacyRenderSubtreeIntoContainer(
// 父节点
parentComponent: ?React$Component<any, any>,
// ReactDOM.render的第一个参数对应的ReactElement
children: ReactNodeList,
// ReactDOM.render的第二个参数
container: DOMContainer,
// 服务端渲染相关
forceHydrate: boolean,
callback: ?Function,
) {
// 在dom节点增加属性_reactRootContainer
let root: Root = (container._reactRootContainer: any);
if (!root) {
// 创建ReactRoot
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
container,
forceHydrate,
);
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function() {
const instance = getPublicRootInstance(root._internalRoot);
originalCallback.call(instance);
};
}
// render方法,放在unbatchedUpdates里面更新
// 意思是当前的更新不需要批量更新,因为是首次渲染,所以会尽快渲染出页面
unbatchedUpdates(() => {
// 执行ReactRoot的render方法
root.render(children, callback);
});
} else {
/** do some things **/
}
return getPublicRootInstance(root._internalRoot);
}TIP
执行legacyCreateRootFromDOMContainer方法实例化ReactRoot,在实例化之前,针对不需要服务端 渲染的情况,假如root节点下存在DOM, 会将原本的DOM节点删除
legacyCreateRootFromDOMContainer方法
typescript
function legacyCreateRootFromDOMContainer(
container: DOMContainer,
forceHydrate: boolean,
): Root {
// 在目前的版本中 concurrent mode 默认是关闭的
const isConcurrent = false;
return new ReactRoot(container, isConcurrent, shouldHydrate);
}DANGER
注意: isConcurrent表示的是是否开启并发模式, 在当前版本中 默认是关闭的
ReactRoot方法的实现
- new ReactRoot的时候,创建了FiberRoot节点
- 在上面的代码中,执行了
root.render, 调用了updateContainer方法做一个具体的更新
typescript
function ReactRoot(
container: DOMContainer,
isConcurrent: boolean,
hydrate: boolean,
) {
// 创建FiberRoot节点
const root = createContainer(container, isConcurrent, hydrate);
this._internalRoot = root;
}typescript
ReactRoot.prototype.render = function(
children: ReactNodeList,
callback: ?() => mixed,
): Work {
const root = this._internalRoot;
updateContainer(children, root, null, work._onCommit);
};创建FiberRoot节点
FiberRoot节点由createContainer方法创建,接着调用createFiberRoot方法
typescript
export function createFiberRoot(
containerInfo: any,
isConcurrent: boolean,
hydrate: boolean,
): FiberRoot {
// 创建RootFiber
const uninitializedFiber = createHostRootFiber(isConcurrent);
// 当前root是FiberRoot
let root = ({
// 指向RootFiber
current: uninitializedFiber,
// 指向root的dom节点
containerInfo: containerInfo,
pendingChildren: null,
pingCache: null,
earliestPendingTime: NoWork,
latestPendingTime: NoWork,
earliestSuspendedTime: NoWork,
latestSuspendedTime: NoWork,
latestPingedTime: NoWork,
didError: false,
pendingCommitExpirationTime: NoWork,
finishedWork: null,
timeoutHandle: noTimeout,
context: null,
pendingContext: null,
hydrate,
nextExpirationTimeToWorkOn: NoWork,
expirationTime: NoWork,
firstBatch: null,
nextScheduledRoot: null,
}: BaseFiberRootProperties);
// 将RootFiber的stateNode指向 FiberRoot
uninitializedFiber.stateNode = root;
return root
}创建RootFiber
typescript
export function createHostRootFiber(isConcurrent: boolean): Fiber {
// 当前版本中,还没有开启ConcurrentMode
let mode = isConcurrent ? ConcurrentMode | StrictMode : NoContext;
if (enableProfilerTimer && isDevToolsPresent) {
mode |= ProfileMode;
}
return createFiber(HostRoot, null, null, mode);
}DANGER
注意看, 当前的RootFiber类型是 HostRoot
至此,创建完了一下基本的节点,然后执行root.render, 调用了updateContainer 方法做一个具体的更新
具体结构如下图
