版本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,
);
},
++實(shí)際調(diào)用legacyRenderSubtreeIntoContainer并設(shè)置它的第四個(gè)參數(shù)shouldHydrate = false 客戶端渲染都是false,true服務(wù)端渲染用于是否復(fù)用子節(jié)點(diǎn)++
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 根據(jù)container初始化創(chuàng)建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. 初始化不批量更新 直接執(zhí)行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屬性,沒(méi)有則賦值創(chuàng)建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下會(huì)對(duì)container dom下的子元素全部刪除,所以大家在html模板下div添加子元素是無(wú)效的蹋凝,最后都會(huì)被刪除++
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 {
// 創(chuàng)建FiberRoot對(duì)象
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.
// 創(chuàng)建rootFiber
const uninitializedFiber = createHostRootFiber(tag);
root.current = uninitializedFiber;
uninitializedFiber.stateNode = root;
return root;
}
++ReactSyncRoot-createRootImpl-createContainer-createFiberRoot調(diào)用順序,最后new FiberRootNode 創(chuàng)建了 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);
};
++后繼續(xù)創(chuàng)建了tag=HostRoot,mode=NoMode的==RootFiber==對(duì)象(createHostRootFiber)++
2.從ReactSyncRoot中取出_internalRoot則創(chuàng)建的FiberRoot對(duì)象趴久,第一次調(diào)用unbatchedUpdates函數(shù)來(lái)不批量更新赌蔑,直接執(zhí)行內(nèi)部的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;
// 計(jì)算新開(kāi)始的時(shí)間
const currentTime = requestCurrentTime();
const suspenseConfig = requestCurrentSuspenseConfig();
// 計(jì)算過(guò)期時(shí)間俯在,用于React優(yōu)先級(jí) 異步
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,
) {
// 根據(jù)expirationTime 創(chuàng)建更新的update
const update = createUpdate(expirationTime, suspenseConfig);
// Caution: React DevTools currently depends on this property
// being called "element".
// 設(shè)置更新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;
}
// 把此次更新入隊(duì)
enqueueUpdate(current, update);
// 進(jìn)行任務(wù)調(diào)度
scheduleWork(current, expirationTime);
return expirationTime;
}
++-根據(jù)currentTime時(shí)間來(lái)計(jì)算expirationTime時(shí)間++
++-創(chuàng)建update對(duì)象,可以根據(jù)next來(lái)指向下個(gè)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對(duì)象放入到updateQueue中++
++-scheduleWork進(jìn)入任務(wù)調(diào)度中++
Todo:expirationTime會(huì)在后續(xù)說(shuō)明
Todo:update,updateQueue會(huì)在后續(xù)說(shuō)明
總結(jié):
- 創(chuàng)建了 ReactRoot對(duì)象
- 創(chuàng)建了FiberRoot,F(xiàn)iberRoot=ReactRoot._internalRoot
- 創(chuàng)建了RootFiber娃惯,F(xiàn)iberRoot.current=RootFiber
- 創(chuàng)建 update
- update入隊(duì)跷乐,scheduleWork進(jìn)入調(diào)度階段
注:在render的第二個(gè)參數(shù)dom,在客戶端渲染會(huì)刪除掉全部的子元素