热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

useEffect和useLayoutEffect的源码解读

文章目录useEffect和useLayoutEffect的源码解读useEffect源码解读mountEffectImplpushEffectupdateEffectImpl疑惑


文章目录


    • useEffect 和 useLayoutEffect 的源码解读
      • useEffect
        • 源码解读
          • mountEffectImpl
            • pushEffect

          • updateEffectImpl
            • 疑惑:



      • useLayOutEffect
        • 源码解读
          • mountLayoutEffect
          • updateLayoutEffect

        • 总结






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 阶段会在不同的时机 调用







推荐阅读
author-avatar
绿茶2602921445
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有