React V17.0源码 学习笔记(一)

602 阅读3分钟

ReactDOM.render 函数调用说明

说明 这里只讨论web端初次调用关于hydrate的全部默认为false|undefinde,不做解释

ReactDOM.render(element,container,callback)

  • element reactElemtn
  • container HtmlElemnt
  • callback 挂载完成后的回调

作用: 渲染挂载的开始

  • 检查 container 是否合法

  • 调用 legacyRenderSubtreeIntoContainer(null,elemrnt,container,false,callback)

legacyRenderSubtreeIntoContainer

  • parentComponent => null --------------- SSR 专用,父结点
  • children => element ------------ 需要渲染的 ReactElemtn
  • container => container ---------- HtmlElment
  • forceHydrate => false -------------- SSR 专用,通过 Hydrate 这里会是 true
  • callBack => callback ----------- 同上

**作用:**根据 container 是否存在 root 区分初始化/更新,创建或获取 fiberRoot,进而启动更新

从 container 取出 _reactRootContainer 作为 react 的一个根

const root = container._reactRootContainer

检查 root 是否存在,如果存在就是 Update,如果不存在就是初始化

若 root 存在

从 root 中取出 fiberRoot

const fiberRoot = root._internalRoot

调用 updateContainer(children,fiberRoot,parentComponent,callBack)

注意:这里 callBack 会通过 getPublicRootInstance() 递归找到 fiberRoot 上第一个非 HTMlElement 结点,并将 callback 绑定在它上边。

if (typeof callback === 'function') {
  const originalCallback = callback;
  callback = function() {
    const instance = getPublicRootInstance(fiberRoot);
    originalCallback.call(instance);
  };
}

若 root 不存在

调用 legacyCreateRootFromDOMContainer(contaiber,forceHydrate) 初始化 root。 将 root 赋值给 container._reactRootContainer,取出 root 中的_internalRoot 作为 fiberRoot。

调用 updateContainer(children,fiberRoot,parentComponent,callBack)。

//注意这里调用的时候,是非批量的。因为是初始化的内部挂载,所以需要使用非批量更新
unbatchedUpdates(() => {
  updateContainer(children, fiberRoot, parentComponent, callback);
});

// updateContainer() 就到了更新流程了,这里不讨论了^-^

legacyCreateRootFromDOMContainer

  • container --------------- HTMLElement
  • forceHydrate ------------ 同上

作用:清空 container,创建 root

  • 根据 forceHydrate 和 container 上是否已经被标记是一个 ReactContainer 来判断是否需要清空 container(SSR 不需要清空,但是 web 端初始化情况)
  • 创建一个 root 结点

shouleHydrate = forceHydrate && isReactContainer(contaiber)?{ hydrate:true }:undefinde

调用 createLegacyRoot(container,shouleHydrate)

createLegacyRoot

  • container --------------- HTMLElement
  • options:shouleHydrate --- 忽略

引入静态变量 LegacyRoot = 0 ,作为 RootTag

调用 new ReactDOMBlockingRoot(container,LegacyRoot,options)

ReactDOMBlockingRoot

  • container --------------- HTMLElement
  • tag --------------------- root 的 tag 表示构建 root 的来源
  • options ----------------- 忽略

创建 RootImpl ,赋值给 this._internalRoot 也就是 fiberRoot

this._internalRoot = createRootImpl(container, tag, options);

//注意:通过 ReactDOMBlockingRoot 创建的实例会自动实现两个函数 render 和 unmount
// 渲染根结点
render(children){
    root = this.\_internalRoot;
    updateContainer(children,root,null,null)
}
// 卸载根结点
unmount(){
    const root = this._internalRoot;
    const container = root.containerInfo;
    updateContainer(null, root, null, () => {
        // 从container中移除 __reactContainer 对应的fiber
        unmarkContainerAsRoot(container);
    });
}

createRootImpl

  • container --------------- HTMLElement
  • tag --------------------- root 的 tag 表示构建 root 的来源
  • options ----------------- 忽略

作用:

  • 根据 container 创建 root
  • 标记 container 作为 root 的 current
  • 为 root 容器添加所有监听事件

根据 container 创建 root

const root = createContainer(container, tag, hydrate, hydrationCallbacks);

标记 container 作为 root 的 current

// 为 container 字段 添加 __reactContainer 对应的 fiber
markContainerAsRoot(root.current, container);

为 root 容器添加所有监听事件

const rootContainerElement = container.nodeType === COMMENT_NODE ? container.parentNode : container;
// 绑定事件监听,特殊处理selectionchange
listenToAllSupportedEvents(rootContainerElement);
createContainer -> createFiberRoot
  • containerInfo --------------- HTMLElement
  • tag ------------------------- root 的 tag 表示构建 root 的来源

作用:

  • 创建 root:FiberRoot

    root = new FiberRootNode(containerInfo,tag)

    -> root.containerInfo = containerInfo

    -> root.tag = tag

  • 创建 RootFiber:Fiber

    RootFiber = createHostRootFiber(tag);

    根据 tag 生成一个 mode,web 初始化出来的 mode === NodeMode

    HostRoot = 3; // 表示创建的是 根结点

    调用 createFiber(HostRoot,null,null,mode)

    -> RootFiber.tag = HostRoot

    -> RootFiber.mode = mode

  • 形成一个闭环,将 root.current 指向 RootFiber,并将 root 作为 Fiber 的第一个 stateNode

    root.current = RootFiber

    RootFiber.stateNode = root

  • 初始化 RootFiber 的 UpdateQueue

    initializeUpdateQueue(RootFiber)

    ->queue.baseState = RootFiber.memoizedState

    ->RootFiber.updateQueus = queue

createFiber
  • tag ------------------------- fiber 的类型
  • penddingProps --------------- 外界数据
  • key ------------------------- 唯一表识
  • mode ------------------------ 基本都是 NodeMode

作用: 生成一个 FiberNode

FiberNode.tag = tag FiberNode.penddingProps = penddingProps FiberNode.mode=mode FiberNode.key = key