版本16.13.0
ReactDOM.render(<App />, document.getElementById('root'));
render(
element: React$Element<any>,
container: DOMContainer,
callback: ?Function,
) {
return legacyRenderSubtreeIntoContainer(
null,
element,
container,
false,
callback,
);
},
++实际调用legacyRenderSubtreeIntoContainer并设置它的第四个参数shouldHydrate = false 客户端渲染都是false,true服务端渲染用于是否复用子节点++
function legacyRenderSubtreeIntoContainer(
parentComponent: ?React$Component<any, any>,
children: ReactNodeList,
container: DOMContainer,
forceHydrate: boolean,
callback: ?Function,
) {
// TODO: Without `any` type, Flow says "Property cannot be accessed on any
// member of intersection type." Whyyyyyy.
let root: _ReactSyncRoot = (container._reactRootContainer: any);
let fiberRoot;
if (!root) {
// Initial mount 根据container初始化创建ReactSyncRoot
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
container,
forceHydrate,
);
// ReactSyncRoot._internalRoot获取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. 初始化不批量更新 直接执行fn
unbatchedUpdates(() => {
updateContainer(children, fiberRoot, parentComponent, callback);
});
} else {
fiberRoot = root._internalRoot;
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function() {
const instance = getPublicRootInstance(fiberRoot);
originalCallback.call(instance);
};
}
// Update
updateContainer(children, fiberRoot, parentComponent, callback);
}
return getPublicRootInstance(fiberRoot);
1. 先判断container(document.getElementById('root')是否有_reactRootContainer属性,没有则赋值创建ReactSyncRoot,legacyCreateRootFromDOMContainer
function legacyCreateRootFromDOMContainer(
container: DOMContainer,
forceHydrate: boolean,
): _ReactSyncRoot {
const shouldHydrate =
forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
// First clear any existing content.
if (!shouldHydrate) {
let warned = false;
let rootSibling;
// !shouldHydrate下遍历containerdom下元素,删除子元素
while ((rootSibling = container.lastChild)) {
container.removeChild(rootSibling);
}
}
// Legacy roots are not batched.
return new ReactSyncRoot(
container,
LegacyRoot,
shouldHydrate
? {
hydrate: true,
}
: undefined,
);
}
++由上可以看到在非shouldHydrate下会对container dom下的子元素全部删除,所以大家在html模板下div添加子元素是无效的,最后都会被删除++
function ReactSyncRoot(
container: DOMContainer, // 非hydrate下删除子元素的dom
tag: RootTag, // LegacyRoot=0类型
options: void | RootOptions,
) {
// _internalRoot = FiberRoot
this._internalRoot = createRootImpl(container, tag, options);
}
function createRootImpl(
container: DOMContainer,
tag: RootTag, // LegacyRoot
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 root = createContainer(container, tag, hydrate, hydrationCallbacks);
markContainerAsRoot(root.current, container);
if (hydrate && tag !== LegacyRoot) {
const doc =
container.nodeType === DOCUMENT_NODE
? container
: container.ownerDocument;
eagerlyTrapReplayableEvents(doc);
}
return root;
}
export function createContainer(
containerInfo: Container,
tag: RootTag,
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
): OpaqueRoot {
return createFiberRoot(containerInfo, tag, hydrate, hydrationCallbacks);
}
export function createFiberRoot(
containerInfo: any, // document.getElementById('root') dom
tag: RootTag, // LegacyRoot=0
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
): FiberRoot {
// 创建FiberRoot对象
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);
root.current = uninitializedFiber;
uninitializedFiber.stateNode = root;
return root;
}
++ReactSyncRoot-createRootImpl-createContainer-createFiberRoot调用顺序,最后new FiberRootNode 创建了 tag=LegacyRoot的==FiberRoot==++
export function createHostRootFiber(tag: RootTag): Fiber {
let mode;
if (tag === ConcurrentRoot) {
mode = ConcurrentMode | BatchedMode | StrictMode;
} else if (tag === BatchedRoot) {
mode = BatchedMode | StrictMode;
} else {
mode = NoMode;
}
if (enableProfilerTimer && isDevToolsPresent) {
// Always collect profile timings when DevTools are present.
// This enables DevTools to start capturing timing at any point–
// Without some nodes in the tree having empty base times.
mode |= ProfileMode;
}
return createFiber(HostRoot, null, null, mode);
}
const createFiber = function(
tag: WorkTag, // HostRoot=3
pendingProps: mixed,
key: null | string,
mode: TypeOfMode, // NoMode
): Fiber {
// $FlowFixMe: the shapes are exact here but Flow doesn't like constructors
return new FiberNode(tag, pendingProps, key, mode);
};
++后继续创建了tag=HostRoot,mode=NoMode的==RootFiber==对象(createHostRootFiber)++
2.从ReactSyncRoot中取出_internalRoot则创建的FiberRoot对象,第一次调用unbatchedUpdates函数来不批量更新,直接执行内部的fn
unbatchedUpdates(() => {
updateContainer(children, fiberRoot, parentComponent, callback);
});
export function updateContainer(
element: ReactNodeList, // app
container: OpaqueRoot, // fiberRoot
parentComponent: ?React$Component<any, any>,
callback: ?Function,
): ExpirationTime {
// fiber的root
const current = container.current;
// 计算新开始的时间
const currentTime = requestCurrentTime();
const suspenseConfig = requestCurrentSuspenseConfig();
// 计算过期时间,用于React优先级 异步
const expirationTime = computeExpirationForFiber(
currentTime,
current,
suspenseConfig,
);
return updateContainerAtExpirationTime(
element,
container,
parentComponent,
expirationTime,
suspenseConfig,
callback,
);
}
export function updateContainerAtExpirationTime(
element: ReactNodeList,
container: OpaqueRoot,
parentComponent: ?React$Component<any, any>,
expirationTime: ExpirationTime,
suspenseConfig: null | SuspenseConfig,
callback: ?Function,
) {
return scheduleRootUpdate(
current,
element,
expirationTime,
suspenseConfig,
callback,
);
}
function scheduleRootUpdate(
current: Fiber,
element: ReactNodeList,
expirationTime: ExpirationTime,
suspenseConfig: null | SuspenseConfig,
callback: ?Function,
) {
// 根据expirationTime 创建更新的update
const update = createUpdate(expirationTime, suspenseConfig);
// Caution: React DevTools currently depends on this property
// being called "element".
// 设置更新payload app组件
update.payload = {element};
callback = callback === undefined ? null : callback;
if (callback !== null) {
warningWithoutStack(
typeof callback === 'function',
'render(...): Expected the last optional `callback` argument to be a ' +
'function. Instead received: %s.',
callback,
);
update.callback = callback;
}
// 把此次更新入队
enqueueUpdate(current, update);
// 进行任务调度
scheduleWork(current, expirationTime);
return expirationTime;
}
++-根据currentTime时间来计算expirationTime时间++
++-创建update对象,可以根据next来指向下个update++
export function createUpdate(
expirationTime: ExpirationTime,
suspenseConfig: null | SuspenseConfig,
): Update<*> {
let update: Update<*> = {
expirationTime,
suspenseConfig,
tag: UpdateState,
payload: null,
callback: null,
next: null,
nextEffect: null,
};
return update;
}
++-把update对象放入到updateQueue中++
++-scheduleWork进入任务调度中++
Todo:expirationTime会在后续说明
Todo:update,updateQueue会在后续说明
总结:
- 创建了 ReactRoot对象
- 创建了FiberRoot,FiberRoot=ReactRoot._internalRoot
- 创建了RootFiber,FiberRoot.current=RootFiber
- 创建 update
- update入队,scheduleWork进入调度阶段
注:在render的第二个参数dom,在客户端渲染会删除掉全部的子元素
网友评论