react源码学习-实现篇-useEffect

useEffect

在这里插入图片描述

在commit阶段的before-mutation阶段之前,会使用scheduleCallback调度useEffect。可以看到useEffect的优先级是普通优先级。
在这里插入图片描述

flushPassiveEffectsImpl

在这里插入图片描述

主要做三件事,1 调用改useEffect在上一次render时的销毁函数; 2 调用该useEffect在本次render的回调函数。 3 存在同步任务的话,就执行他,不需要等到下次事件循环的宏任务。

1 调用useEffect的销毁函数。

commitPassiveUmmountEffects最终会调用这个commitHookEffectListUnmount函数,他会遍历

在这里插入图片描述

Effectlist,然后调用destory函数。useEffect的执行需要保证所有组件的useEffect的销毁函数执行完才能执行,因为多个组件可能公用一个ref,如果不是按照全部销毁再全部执行的顺序,那么组件的useEffect的销毁函数修改的ref.current可能影响另一个组件useEffect的执行。

2 调用useEffect的执行函数

在这里插入图片描述

遍历effectList,然后执行回调函数,获取destroy,存放在effect上,effect就是带有effectTag的fiber。

这就是useEffect的执行流程。

useEffect的调度顺序就是:

1 commit阶段的before-mutation阶段之前通过scheduleCallback进行调度flushPassiveEffects函数。

2 因为flushPassiveEffects函数会遍历effect,所以layout阶段之后,会将effectList放入一个全局变量。

3 适当的时机,useEffect会在页面渲染后,即layout阶段后执行。

4 flushPassiveEffects做的事情就是:获取effectList,遍历执行effect的useEffect销毁函数,然后再遍历执行effect的useEffect执行函数,将destory存放在每个fiber.destory上。

useRef

先看看useRef在mount和update的不同函数。

在这里插入图片描述

在这里插入图片描述

可以看到,创建了一个hooks结构,返回的是一个{current: xx}的值,而且存在了hook.memoizedState,对应之前说的useRef的hooks的数据结构存放memoizedState。

在这里插入图片描述

update的时候就简单粗暴了,直接返回hook.memoizedState.

ref的工作流程

在rect中,HostComponent和calssComponent可以赋值ref属性,而ForwardRef只是把ref传下去。

对于hostComponent,在commit阶段的mutation执行dom操作。对应的ref更新也是在mutation阶段。如果hostComponent或者classComponent有ref,那么
在这里插入图片描述

也会赋值对应的effectTag。

所以ref的工作流程分为两部分:

  • 1 render阶段为含有ref属性的fiber添加Ref effectTag。
  • 2 commit阶段为包含Ref effectTag的fiber执行对应操作。
render阶段

在beginwork阶段,

updateHostComponent和finishClassComponent会调用(对应hostComponent和classComponent)
在这里插入图片描述

,对其赋值ref属性。

在completeWork阶段,对于HostComponent,
在这里插入图片描述

如果当前的ref和之前保存的ref不同。表示原生组件的ref该换了。

commit阶段

在这里插入图片描述

mutation阶段,对于ref属性改变的情况,需要移除之前的ref。

而赋值是在layout阶段执行的

在这里插入图片描述

function commitAttachRef(finishedWork: Fiber) {
  const ref = finishedWork.ref;
  if (ref !== null) {
    // 获取ref属性对应的Component实例
    const instance = finishedWork.stateNode;
    let instanceToUse;
    switch (finishedWork.tag) {
      case HostComponent:
        instanceToUse = getPublicInstance(instance);
        break;
      default:
        instanceToUse = instance;
    }

    // 赋值ref
    if (typeof ref === 'function') {
      ref(instanceToUse);
    } else {
      ref.current = instanceToUse;
    }
  }
}

至此ref的工作流程完毕。

总结:hostComponent和classComponent的ref是在render阶段被赋予effectTag属性,然后在commit阶段的时候,mutation阶段会判断ref是否变化,变化就去掉ref,然后在layout阶段重新赋值。

useMemo useCallback

mount的时候

在这里插入图片描述

在这里插入图片描述

之前介绍hooks的数据结构就说过,useMemo, useCallback创建的hooks上的memoizedState上存放着对应的值和依赖项。

创建hooks,useMemo会执行函数,然后将值和依赖项存储起来。

而useCallback会存粗函数和依赖项。

update的时候

在这里插入图片描述

在这里插入图片描述

再执行的时候,两者都会获取依赖项,然后进行匹配,如果改变就返回新的值,如果没改变,那么就返回存储在hooks的值。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coderlin_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值