|
|
|
@ -3,6 +3,7 @@
@@ -3,6 +3,7 @@
|
|
|
|
|
> React 从 16 开始,对底层架构做了一次重构,和 15 不同,渲染 vdom 的时候一改以往的递归执行,引入了一个新的概念,叫做 Fiber,虽然最后渲染到页面的时候还是递归,但是 Fiber 的递归是可以中断的,根据优先级由浏览器优先执行任务,保证在大量视图需要更新的时候,浏览器仍然能保证快速的响应 |
|
|
|
|
|
|
|
|
|
在 React 中,视图的更新使用了双缓存的方式,也就是说在 React 运行时,同时有着两棵 Fiber 树,一颗是当前视图上的 Fiber 树,叫 current,另外一棵是存在内存当中的下一次视图更新时用的叫做 workInProgress,React 在构建时会创建整个 app 唯一的根 Fiber 节点,叫做 FiberRootNode,这个节点上有一个 current 指针,指向的是当前正在页面上显示的 Fiber 树也就是 current,当 workInProgress 递归生成完毕,指针会立即指向 workInProgress ,而旧的 current 就会在下一次渲染中变成 workInProgress ,就这样循环交替完成页面的递归渲染 |
|
|
|
|
本次源代码解读的 DEMO 只用了最简单的 useState 做计数器修改触发页面刷新,并没有新增新的DOM 节点之外的其他操作 |
|
|
|
|
|
|
|
|
|
## 首屏渲染 |
|
|
|
|
|
|
|
|
@ -20,7 +21,7 @@ createWorkInProgress 之后,Fiber 的操作就会交由 beginWork 和 complete
@@ -20,7 +21,7 @@ createWorkInProgress 之后,Fiber 的操作就会交由 beginWork 和 complete
|
|
|
|
|
1. 新旧 props 是否相同 |
|
|
|
|
2. Context 是否发生变化 |
|
|
|
|
3. Fiber 节点 type 是否发生变化 |
|
|
|
|
在本次首屏渲染中,以上的条件都为否,会进入后续条件判断,在后续的条件判断中主要是为了应付一些特殊的场景,例如错误边界和 legacy 模式,具体可以看到官方留下的代码注释,在我们现在的场景下,最终会走到 didReceiveUpdate 为 false 的情况下,也就是当前 Fiber 并没有变化,因为在之前的 createWorkInProgress 中 WorkFiberProgress 被赋值上了 current Fiber 的同名属性,所以它们会是相同的两个 FIber 节点,在这里的代码可以看到:beginWork 中还有对优先值 lanes 的一些处理,在这里先不展开,后续再补充 |
|
|
|
|
在本次首屏渲染中,以上的条件都为否,会进入后续条件判断,在后续的条件判断中主要是为了应付一些特殊的场景,例如错误边界和 legacy 模式,可以看到官方留下的代码注释,在我们现在的场景下,最终会走到 didReceiveUpdate 为 false 的情况下,也就是当前 Fiber 并没有变化,因为在之前的 createWorkInProgress 中 WorkFiberProgress 被赋值上了 current Fiber 的同名属性,所以它们会是相同的两个 FIber 节点,在这里的代码可以看到:beginWork 中还有对优先值 lanes 的一些处理,在这里先不展开,后续再补充 |
|
|
|
|
最后会走入 switch 环节,这了主要根据传入的 WorkInProgress Fiber 节点的类型进入不同的处理逻辑,这也是 beginWork 最主要的任务:为当前 WorkInProgress Fiber 节点创建它的第一个 Fiber 子节点,其内部根据 Fiber 的 tag 不同有对应的: |
|
|
|
|
- updateClassComponent 处理 Class Component |
|
|
|
|
- updateHostComponent 处理 Host Component |
|
|
|
@ -58,6 +59,9 @@ createInstance 会调用 createElement 方法创建一个 DOM 实例,并调用
@@ -58,6 +59,9 @@ createInstance 会调用 createElement 方法创建一个 DOM 实例,并调用
|
|
|
|
|
### createWorkInProgress |
|
|
|
|
还是交由 createWorkInProgress 这个函数,这个函数会从 current 中取出 alternate 属性,用于判断是否已经存在 WorkInProgress 树,在本次更新,当前的 current 就是上一次渲染的 WorkInProgress,首屏渲染完成之后,实际上只渲染完成了一棵树,但是这次的 WorkInProgress 并不会走等于 null 的逻辑,因为在首屏渲染的时候,那个还是 current 的 WorkInProgress 实际上已经有一个 Fiber 节点了,那就是 FiberNode ,所以在这次渲染,它也还是有那一个 FiberNode 的,所以会走不为空的逻辑:复用现有的 Fiber 节点,其他和首屏渲染是一样的,这里不多赘述 |
|
|
|
|
|
|
|
|
|
### beginWork |
|
|
|
|
第一次触发更新,进入这个函数的逻辑前边和首屏渲染是都是一样的,但是在判断组件是否发生修改的时候逻辑和首屏渲染并不同 |
|
|
|
|
|
|
|
|
|
### 第二次触发更新 |
|
|
|
|
|
|
|
|
|
### 后续触发更新 |