render(
element: React$Element<any>,
container: DOMContainer,
callback: ?Function,
) {
// 注意下 forceHydrate 參數(也就是第四個參數),爲 true 時是服務端渲染
// 調用 render 函數的話這個值永遠爲 false,調用 hydrate 函數的話這個值會爲 true
return legacyRenderSubtreeIntoContainer(
null,
element,
container,
false,
callback,
);
}
複製代碼
沒有root節點,建立一個新的react
function legacyRenderSubtreeIntoContainer(
parentComponent: ?React$Component<any, any>,
children: ReactNodeList,
container: DOMContainer,
forceHydrate: boolean,
callback: ?Function,
) {
// 一開始進來 container 上是確定沒有這個屬性的
let root: Root = (container._reactRootContainer: any);
// 沒有 root 會執行 if 中的操做
if (!root) {
// Initial mount
// 建立一個 root 出來,類型是 ReactRoot,而且掛載到container._reactRootContainer上
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
container,
forceHydrate,
);
}
}
複製代碼
返回ReactRoot的實例bash
function legacyCreateRootFromDOMContainer(
container: DOMContainer,
forceHydrate: boolean,
): Root {
const shouldHydrate =
forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
// forceHydrate爲false,因此進if的判斷
if (!shouldHydrate) {
let warned = false;
let rootSibling;
// container 內部若是有元素的話,就所有清掉
// 可是通常來講咱們都是這樣寫 container 的: <div id='root'></div>
// 因此說 container 內部不要寫任何的節點,一是會被清掉,二是還要進行 DOM 操做,可能還會涉及到重繪迴流等等
while ((rootSibling = container.lastChild)) {
container.removeChild(rootSibling);
}
}
// Legacy roots are not async by default.
// 對於 Root 來講不須要異步
const isConcurrent = false;
return new ReactRoot(container, isConcurrent, shouldHydrate);
}
複製代碼
返回建立FiberRoot方法,而且ReactRoot實例經過_internalRoot關聯數據結構
function ReactRoot(
container: DOMContainer,
isConcurrent: boolean,
hydrate: boolean,
) {
// 這個 root 指的是 FiberRoot
const root = createContainer(container, isConcurrent, hydrate);
this._internalRoot = root;
}
function createContainer(
containerInfo: Container,
isConcurrent: boolean,
hydrate: boolean,
): OpaqueRoot {
return createFiberRoot(containerInfo, isConcurrent, hydrate);
}
複製代碼
建立FiberRoot節點和RootFiber,他們之間相互引用,對於 FiberRoot 對象來講,咱們如今只須要了解兩個屬性,分別是 containerInfo 及 current。前者表明着容器信息,也就是咱們的 document.querySelector('#root');後者指向 RootFiber架構
對於 RootFiber 對象來講,咱們須要瞭解的屬性稍微多點.return、child、sibling 這三個屬性很重要,它們是構成 fiber 樹的主體數據結構。fiber 樹實際上是一個單鏈表樹結構,return 及 child 分別對應着樹的父子節點,而且父節點只有一個 child 指向它的第一個子節點,即使是父節點有好多個子節點。那麼多個子節點如何鏈接起來呢?答案是 sibling,每一個子節點都有一個 sibling 屬性指向着下一個子節點,都有一個 return 屬性指向着父節點。異步
最後是 alternate 屬性。其實在一個 React 應用中,一般來講都有兩個 fiebr 樹,一個叫作 old tree,另外一個叫作 workInProgress tree。前者對應着已經渲染好的 DOM 樹,後者是正在執行更新中的 fiber tree,還能便於中斷後恢復。兩棵樹的節點互相引用,便於共享一些內部的屬性,減小內存的開銷(double buffering)。async
function createFiberRoot(
containerInfo: any,
isConcurrent: boolean,
hydrate: boolean,
): FiberRoot {
// FiberRootNode 內部建立了不少屬性
const root: FiberRoot = (new FiberRootNode(containerInfo, hydrate): any);
// Cyclic construction. This cheats the type system right now because
// stateNode is any.
// 建立一個 root fiber,這也是 React 16 中的核心架構了
// fiber 其實也會組成一個樹結構,內部使用了單鏈表樹結構,每一個節點及組件都會對應一個 fiber
// FiberRoot 和 Root Fiber 會互相引用
// 另外若是你有 React 寫的項目的話,能夠經過如下代碼找到 Fiber Root,它對應着容器
// document.querySelector('#root')._reactRootContainer._internalRoot
const uninitializedFiber = createHostRootFiber(isConcurrent);
root.current = uninitializedFiber;
uninitializedFiber.stateNode = root;
return root;
}
複製代碼
Fiber樹圖解函數