书籍传送门:React技术揭秘——卡颂
前言:整篇文章,我都将以
问题
+笔记
的形式作为精读的导语展开叙述~文末有彩蛋喔~~~
上一篇文章中,我们已经了解了fiber
架构,fiber
思想以及React fiber
的设计理念,本篇,我们着重了解架构篇:
React 架构篇
分为Render
&Commit
两个阶段;
Render 阶段做了什么事?
Render
阶段可以简单描述为:先遍历—>后递归。遍历diff
、递归build dom
;
Render
阶段细分为:beginWork
& completeWork
beginWork
- 传入
当前 fiber
节点,创建子fiber
节点function beginWork( current: Fiber | null, workInProgress: Fiber, renderLanes: Lanes, ): Fiber | null { // ...省略函数体 }
current
指的是wip.alternate
,也就是当前组件上一次更新时的fiber
节点;workInProgress
指的是当前组件的fiber
;renderLanes
指的是优先级
;
- 传入
可以通过current !== null
来区分是mount
还是update
,基于此,beginWork
又可以分为两个阶段:mount
&update
.
mount
阶段,会根据不同的fiber.tag
创建不同的fiber
节点。
update
阶段
- 会根据
props
与fiber.type
的比对决定是否要复用fiber
节点 - 根据
renderLanes
判断优先级,配合Schedule
去实现任务调度
问题:如果不能复用,怎么办呢?
答:进入diff
,交给reconcile
去处理。
beginWork
结束后,就会进入reconcileChildren
.也就是传说中的diff算法
注意
值得一提的是,mountChildFibers 与 reconcileChildFibers 这两个方法的逻辑基本一致。唯一的区别是:reconcileChildFibers 会为生成的 Fiber 节点带上 effectTag 属性,而 mountChildFibers 不会。
在reconcileChildren
结束后,紧接着就是根据diff
结果为fiber
打上effetTag
,例如:它是增、改、还是删等。
// DOM需要插入到页面中
export const Placement = /* */ 0b00000000000010;
// DOM需要更新
export const Update = /* */ 0b00000000000100;
// DOM需要插入到页面中并更新
export const PlacementAndUpdate = /* */ 0b00000000000110;
// DOM需要删除
export const Deletion = /* */ 0b00000000001000;
小疑问:mount
阶段也会打Placement
tag,那么执行 插入操作会不会很低效?
答:mount
阶段确实会打Placement
tag,但是是在rootFiber
上打的。
completeWork
跟 beginWork
一样,都是根据不同的tag
去做不同的处理。
update
- 处理事件相关的回调函数的注册
- 处理
style prop
- 处理
DANGEROUSLY_SET_INNER_HTML prop
- 处理
children prop
mount
删除的文字是卡老师
原文中的,但是,我觉得只要没渲染到页面上,它就还是Fiber
树~正好跟上缓存的概念相对应。
为为Fiber
节点生成对应的DOM
节点Current Fiber
[屏幕上显示的]节点生成对应的WIP Fiber
[正在内存中构建的]节点。将子孙将子孙DOM
节点插入刚生成的DOM
节点中Fiber
节点插入刚生成的Fiber
节点中。- 与
update
相似的的处理props