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树图解函数