useEffect 和 useLayoutEffect 的源码解读

useEffect 和 useLayoutEffect 的源码解读

useEffect

文件在 packages/react-reconciler/src/ReactFiberHooks.old.js

源码解读

在这里插入图片描述
在这里插入图片描述

根据上一篇 useState 的经验可知,useEffect 在 mount 的时候,会调用 mountEffectImpl 函数,在 update 的时候,会调用 updateEffectImpl 函数

在这里插入图片描述

mountEffectImpl
  1. 首先调用 mountWorkInProgressHook 获取当前 hook对应的数据

  2. 获取 effect 对应的 依赖项

  3. 为当前 fiber 的 flags 增加上 该hook的 fiberFlags(这个 fiberFlags 对于 useEffect 和 useLauoutEffect 是不同的,所以用于区分这两者)

  4. 将pushEffect函数返回的 新的 effect 赋值给 hook.memoizedState

    (注意:对于 useState 来说,memoizedState 保存的是状态,而 useEffect 来说,memoizedState 实际上是保存的 当前hook上最后一个 effect 数据)

在这里插入图片描述

pushEffect

判断 componentUpdateQueue 是否存在,若存在,就为这个环状链表附加一个 effect;若不存在,就新建一个环状链表

  1. 首先会创建一个变量 componentUpdateQueue,并被赋值给 currentlyRenderingFiber.updateQueue

    updateQueue 的数据结构是:

  2. 若 componentUpdateQueue 不存在,把创建的数据结构 effect 挂载到 componentUpdateQueue.lastEffect 上,并且effect 与自己形成一条环状链表(与 update 的时候,数据结构类似)

  3. effect数据结构:(结合 useEffect 的API,判断以下)

    1. create :是 useEfect 的回调函数
    2. destroy:useEfect 的回调函数的返回值的 那个函数
  4. 若 componentUpdateQueue 存在,则在环状链表后面新加上一个 effect

  5. 最终返回本次创建的 effect

在这里插入图片描述

updateEffectImpl

useEffect 在 mount 和 update 阶段有什么区别吗?

在 update时,前一个 useEffect 已经被执行过了,所以说前一个 useEffect 可能存在他的 destory 函数

  1. 从currentHook.memoizedState中取出 上一次 更新的 effect,即 prevEffect
  2. 再从 prevEffect 中取出 destory 函数(注意:需要上一次 effect 中的 create 执行完之后 ,才会有 上一次 effect 的 destory 函数)
  3. 判断 上一次的 deps 和 这一次的 deps 比较是否相等:不论是否相等,都会pushEffect,只是区别在于一个 hookHasEffect 参数。若相等,在 pushEffect 函数的第一个参数是直接传一个 hookFlags 参数,若不相等,是传的 HookHasEffect | hookFlags
疑惑:

为什么要在 deps 没有改变的情况下,还要 pushEffect 呢?

解答:

在 函数组件中,所有 hook 是保存在 fiber.memoizedState 上,并且会形成一个单向的环状链表,这些 hooks 的调用顺序都是不变的,同样,对于 useEffect 和 useLayoutEffect,也是保存在一条单向链表上的,顺序也不能改变。所以即使本次更新 deps 没有改变,不会调用 hooks 对应的回调函数,我们也需要 pushEffect,确保hooks的环状链表在整个更新中都是能对应的上的

在这里插入图片描述

useLayOutEffect

源码解读

在 mount 阶段时,调用 mountLayoutEffect 函数,在 update 阶段时,调用 updateLayoutEffect

mountLayoutEffect

可以看出 mountLayoutEffect 最终也是调用 mountEffectImpl 函数,只不过 传入的第二个参数是 HookLayout
在这里插入图片描述

updateLayoutEffect

和 mountLayoutEffect 同理,也是调用的 updateEffectImpl, 传入的第二个参数是 HookLayout

在这里插入图片描述

总结

所以 useEffect 和 useLayoutEffect 他的整体运行流程基本一致,唯一不同的是 在 commit 阶段会在不同的时机 调用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值