React 执行架构流程详细----归阶段 mount 时流程(三)
引言
由前一篇可知:
-
render 阶段就是采用dfs的方式依次执行fiber节点的 beginWork 和 completeWork
-
整个 React 执行分为四个阶段,今天阐述第二个阶段:归阶段 mount 时流程
归阶段 mount 时流程
也就是 mount 阶段 completeWork 的流程
🌰
- 对于以下这个结构来说:
- 第一个进入 completework 的节点是 img ,会根据 fiber节点的 type 进入不同的 case
img 节点是 host component ,所以进入这个case:
- 首先会判断 current 是否存在,首次渲染时 current 是不存在的,接下来会为 hostcomponent 对应的 fiber 节点创建对应的 DOM 节点,进入 createInstance 函数:
- 可以看到 在 createInstance 中执行了 createElement 函数,domElement 就是 img DOM 元素
- 当创建完dom 节点后,会通过 appendAllChildren 函数 将这个节点插入到到之前已经创建好的dom树中。
appendAllChildren 的作用:将已经创建好的dom节点挂载到当前dom 树下,当我们 归阶段,从每一个子节点一路向上,归到根节点时,创建的每一个子节点都会挂载到它的父级dom节点下,当执行到 App 节点时,就已经有一棵构建好的 dom 树
- 接下来会将 img dom 节点保存在 img 对应的 fiber 节点的 stateNode 属性上
- 最后在 finalizeInitialChildren 给 dom 节点设置一些属性,img 节点上加上了 alt,className 等属性
- 进入 setInitialProperties 函数:
首先会判断这是否是一个自定义标签,接下来会根据 hostcomponent 的 tag 来进入不同的逻辑
再判断props 是否合法,再进入初始化 dom 属性的操作
属性类型不同做不同的处理
最终会调用 setAttribute 进行属性赋值:
即一个 fiber 节点的 completework 就完成了,之后就进入下一个 fiber 节点的 completework
PS:对于以下类型的组件,是没有 completeWork 的逻辑的
总结
- 会判断当前fiber节点的类型,进入不同的 case(比如说是 HostComponent,就进入相关的 case)
- 首先会判断 current 是否存在
- 为 HostComponent 对应的 fiber 节点创建对应 的 DOM 节点,会将这个DOM节点保存在 该fiber 的 stateNode 上,然后再为DOM 节点设置一些属性(初始化属性)
- 将创建好的节点插入到 DOM 树中:每一个 hostComponent 在 appendChildren 函数中,执行挂载
- 然后就进入下一个 fiber 节点的 completeWork 的过程
- 当整个应用的所有节点都执行完了 completeWork 时,将 root node 的标记 effectTag 置为 placement,就能将整棵 树进行挂载到页面上
解决问题
问题提出
在 reconcileChildren 中,当某个 fiber 节点不存在对应的 current 节点时,他是不会被标记 effectTag 的,那么首屏渲染的时候,这些 DOM 节点是如何挂载到页面中的呢?
解答
对于首屏渲染,会有一个节点进入 reconcileChildFibers 逻辑,这个存在 current 节点的就是当前应用的根节点,即下图中的 FiberRootNode
之后会进入 reconcileSingleElement 函数:
进入 placeSingleChild :App 节点的effectTag会被赋值为 placement
只需要在App这一级有一个 Placement 的 effectTag ,就能将整棵 dom树挂载到页面上,这就是首屏渲染的 dom插入逻辑
参考资料:
React 项目源码
技术揭秘
React 版本是17