gpt4 book ai didi

简单分析React中的EffectList

转载 作者:qq735679552 更新时间:2022-09-28 22:32:09 40 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章简单分析React中的EffectList由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

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.

简化代码如下.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
function completeUnitOfWork(unitOfWork: Fiber): void {
  let completedWork = unitOfWork;
  do {
   const current = completedWork.alternate;
   const returnFiber = completedWork. return ;
  
   let next= completeWork(current, completedWork, subtreeRenderLanes);
 
   // effect list构建
   if (
    returnFiber !== null &&
    (returnFiber.flags & Incomplete) === NoFlags
   ) {
    // 层层拷贝
    if (returnFiber.firstEffect === null ) {
     returnFiber.firstEffect = completedWork.firstEffect;
    }
    if (completedWork.lastEffect !== null ) {
     // 说明当前节点是兄弟节点,子节点有effect,已经给returnFiber.lastEffect赋值过了
     if (returnFiber.lastEffect !== null ) {
      // 连接兄弟节点的effect
      returnFiber.lastEffect.nextEffect = completedWork.firstEffect;
     }
     returnFiber.lastEffect = completedWork.lastEffect;
    }
   
    const flags = completedWork.flags;
   
    // 该fiber节点有effect
    if (flags > PerformedWork) {
     // 当前节点有effect连接上effect list
     if (returnFiber.lastEffect !== null ) {
      returnFiber.lastEffect.nextEffect = completedWork;
     } else {
      // returnFiber没有firstEffect的情况是第一次遇见有effect的节点
      returnFiber.firstEffect = completedWork;
     }
     returnFiber.lastEffect = completedWork;
    }
   }
 
   // 兄弟元素遍历再到返返回父级
   const siblingFiber = completedWork.sibling;
   if (siblingFiber !== null ) {
    workInProgress = siblingFiber;
    return ;
   }
   completedWork = returnFiber;
   workInProgress = completedWork;
  } while (completedWork !== null );
}

EffectList实际是像冒泡一样,一层一层不断向上层收集,从第一个有flags的节点开始记录,每层的新节点都会将上一个节点的firstEffect和lastEffect拷贝到自身身上,再供上层节点再次拷贝.

如以下结构,假如每一个div都有flags.

?
1
2
3
4
5
6
< div id = "1" >
  < div id = "4" />
  < div id = "2" >
   < div id = "3" />
  </ div >
</ div >

最终形成的EffectList为 。

?
1
2
firstEffect => div4
lastEffect => div1

因为Fiber树的构建深度优先,所有div4先完成completeWork,构建firstEffect.

EffectList遍历是从firstEffect开始,通过每一个节点的nextEffect找到下一个节点.

?
1
2
3
4
firstEffect => div4
div4.nextEffect => div3
div3.nextEffect => div2
div2.nextEffect => div1

初次Render时的EffectList

在React中,会对初次Mount有一个性能优化,其中的Fiber节点的flags不会包含placement,对应的DOM节点不会遍历加入DOM树,而是在创建DOM节点时就已经加入DOM树了,只有rootFiber节点FiberRootNode的flags会包含placement.

EffectList是不会包含root节点的,所以需要将root节点也添加到EffectList,这样才会正确的执行placement,让DOM树在页面呈现 .

?
1
2
3
4
5
6
7
8
9
10
11
12
13
let firstEffect;
// 把根节点finishedWork也连接进去
if (finishedWork.flags > PerformedWork) {
  if (finishedWork.lastEffect !== null ) {
   finishedWork.lastEffect.nextEffect = finishedWork;
   firstEffect = finishedWork.firstEffect;
  } else {
   firstEffect = finishedWork;
  }
} else {
  // 根节点没有effect.
  firstEffect = finishedWork.firstEffect;
}

EffectList的遍历

EffectList的主要是用于Layout阶段生命周期方法的执行和DOM的操作.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 处理getSnapshotBeforeUpdate,调度useEffect
nextEffect = firstEffect;
do {
  commitBeforeMutationEffects();
} while (nextEffect !== null );
// DOM操作
nextEffect = firstEffect;
do {
  commitMutationEffects(root, renderPriorityLevel);
} while (nextEffect !== null );
// 生命周期方法的执行
nextEffect = firstEffect;
do {
  commitLayoutEffects(root, lanes);
} while (nextEffect !== null );

在这Layout阶段的这3个方法里,会遍历nextEffect,每执行完一个,就重新指向firstEffect。Layout阶段具体操作就不细讲了.

总结

EffectList不是全局变量,只是在Fiber树创建过程中,一层层向上收集有effect的Fiber节点,最终的root节点就会收集到所有有effect到Fiber节点,我们就把这条包含effect节点的链表叫做EffectList.

由于收集的过程是深度优先,子级会先被收集,所以遍历的时候也会先操作子级,所以如果有面试官问子级和父级的生命周期或者useEffect谁先执行,就很清楚的知道会先执行子级操作了.

以上就是简单分析React中的EffectList的详细内容,更多关于React中的EffectList的资料请关注我其它相关文章! 。

原文链接:https://juejin.cn/post/6947168516394975239 。

最后此篇关于简单分析React中的EffectList的文章就讲到这里了,如果你想了解更多关于简单分析React中的EffectList的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

40 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com