浅析React中的EffectList #115
zhangyu1818
announced in
zh-cn
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
React中,会遍历EffectList来执行节点操作、生命周期方法、Effect方法,可以把EffectList比作圣诞树上挂的彩灯,而这颗圣诞树就是Fiber树。
为什么会存在EffectList呢?打个比方来说,一颗Fiber树中有一些Fiber节点需要执行
componentDidMount
方法,如果在Fiber树构建完成后,再遍历一次Fiber树,找到需要执行componentDidMount
方法的Fiber节点,这是非常低效的。而EffectList就解决了这个问题,在Fiber树构建过程中,每当一个Fiber节点的
flags
字段不为NoFlags
时(代表需要执行副作用),就把该Fiber节点添加到EffectList,在Fiber树构建完成后,由Fiber节点串成的彩灯也构建完成了,这样仅仅需要遍历彩灯就行了。EffectList的收集
EffectList是一个单向链表,
firstEffect
代表链表中的第一个Fiber节点,lastEffect
代表链表中的最后一个Fiber节点。Fiber树的构建是深度优先的,也就是先向下构建子级Fiber节点,子级节点构建完成后,再向上构建父级Fiber节点,所以EffectList中总是子级Fiber节点在前面。
Fiber节点构建完成的操作执行在
completeUnitOfWork
方法,在这个方法里,不仅会对节点完成构建,也会将有flags
的Fiber节点添加到EffectList。简化代码如下。
EffectList实际是像冒泡一样,一层一层不断向上层收集,从第一个有
flags
的节点开始记录,每层的新节点都会将上一个节点的firstEffect
和lastEffect
拷贝到自身身上,再供上层节点再次拷贝。如以下结构,假如每一个
div
都有flags
。最终形成的EffectList为
因为Fiber树的构建深度优先,所有
div4
先完成completeWork
,构建firstEffect
。EffectList遍历是从
firstEffect
开始,通过每一个节点的nextEffect
找到下一个节点。特殊情况
当节点需要删除时,会提前将此节点添加到EffectList中,这一步发生在
beginWork
。初次Render时的EffectList
在React中,会对初次Mount有一个性能优化,其中的Fiber节点的
flags
不会包含placement
,对应的DOM节点不会遍历加入DOM树,而是在创建DOM节点时就已经加入DOM树了,只有root
Fiber节点FiberRootNode
的flags
会包含placement
。EffectList是不会包含
root
节点的,所以需要将root
节点也添加到EffectList,这样才会正确的执行placement
,让DOM树在页面呈现 。EffectList的遍历
EffectList的主要是用于Layout阶段生命周期方法的执行和DOM的操作。
在这Layout阶段的这3个方法里,会遍历
nextEffect
,每执行完一个,就重新指向firstEffect
。Layout阶段具体操作就不细讲了。总结
EffectList不是全局变量,只是在Fiber树创建过程中,一层层向上收集有
effect
的Fiber节点,最终的root
节点就会收集到所有有effect
到Fiber节点,我们就把这条包含effect
节点的链表叫做EffectList。由于收集的过程是深度优先,子级会先被收集,所以遍历的时候也会先操作子级,所以如果有面试官问子级和父级的生命周期或者
useEffect
谁先执行,就很清楚的知道会先执行子级操作了。Beta Was this translation helpful? Give feedback.
All reactions