最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • useEffect 与 useLayoutEffect的区别

    正文概述 掘金(Alander)   2021-07-25   723

    前置知识

    我们可以将 React 的工作流程划分为几大块:

    1. render 阶段:主要生成 Fiber节点 并构建出完整的 Fiber树
    2. commit 阶段:在上一个render 阶段中会在 rootFiber 上生成一条副作用链表,应用的DOM操作就会在本阶段执行

    commit阶段的工作主要分为三部分,对应到源码中的函数名是:

    • commitBeforeMutationEffects阶段:主要处理执行DOM操作前的一些相关操作
    • commitMutationEffects阶段:执行DOM操作
    • commitLayoutEffects阶段:主要处理执行DOM操作后的一些相关操作

    useEffectuseLayoutEffect 的区别主要就在体现在这三个阶段的处理上。结论是:useEffect 会异步地去执行它的响应函数和上一次的销毁函数,而useLayoutEffect 会同步地执行它的响应函数和上一次的销毁函数,即会阻塞住 DOM渲染

    useEffect

    commitBeforeMutationEffects

    在这个阶段中 useEffect 着重会经历一句话如下:

    function commitBeforeMutationEffects() {
      while (nextEffect$1 !== null) {
        // 一系列的赋值操作省略,这里的flags应取自对应FunctionComponent的effect的flags,具体实现请看源码
        var flags = effect.flags;
    
    		// 处理生命周期
        if ((flags & Snapshot) !== NoFlags) {
          setCurrentFiber(nextEffect$1);
          commitBeforeMutationLifeCycles(current, nextEffect$1);
          resetCurrentFiber();
        }
    
    	// 这个if判断只有 useEffect 为 true,useLayoutEffect 为false
        if ((flags & Passive) !== NoFlags) {
          // If there are passive effects, schedule a callback to flush at
          // the earliest opportunity.
          if (!rootDoesHavePassiveEffects) {
            rootDoesHavePassiveEffects = true;
    	// 这里就是 useEffect 异步的原因,DOM操作后React会调度 flushPassiveEffects
            scheduleCallback(NormalPriority, function () {
              flushPassiveEffects();
              return null;
            });
          }
        }
    
        nextEffect$1 = nextEffect$1.nextEffect;
      }
    }
    

    commitMutationEffects

    在这个阶段中,React 会进行一系列的DOM节点更新 ,然后会执行一个方法: commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);

    那么一个拥有 useEffectFunctional Component 在这个阶段是不符合 unmount 的判断逻辑的,所以在这个地方不会做 unmount 操作。

    commitLayoutEffects

    在这个阶段中,依然有一个很重要的方法存在:commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);

    这个if判断和上一阶段的if判断是一样的,useEffec 在这个判断中不会做任何操作。

    后续阶段

    在完成了 commitLayoutEffects 后,还有一个操作:

    if (rootDoesHavePassiveEffects) {
        // This commit has passive effects. Stash a reference to them. But don't
        // schedule a callback until after flushing layout work.
        rootDoesHavePassiveEffects = false;
        rootWithPendingPassiveEffects = root;
        pendingPassiveEffectsLanes = lanes;
        pendingPassiveEffectsRenderPriority = renderPriorityLevel;
      }
    

    即把 rootWithPendingPassiveEffects 置为 root ,这么做的原因和第一阶段 commitBeforeMutationEffectsuseEffect 注册的下一次 flushPassiveEffects 异步调度有关,我们看以下 flushPassiveEffects 的实现:

    function flushPassiveEffectsImpl() {
    	if (rootWithPendingPassiveEffects === null) {
        return false;
      }
    	// 省略一系列的性能追踪等操作
    	commitPassiveUnmountEffects(root.current);
      commitPassiveMountEffects(root, root.current);
    }
    
    

    从上述代码段可以看见,useEffect 在第一阶段注册的调度回调会在页面更新后进行 unmountmount 操作。值得一提的是,这个回调中effect的注册时机就是在 commitLayoutEffects 阶段。

    useLayoutEffect

    其实根据我们对 useEffect 的解析来看,就是在 commitMutationEffectscommitLayoutEffects 阶段中各自的 if 判断中,useLayoutEffect 是通过if判断的,所以在 commitMutationEffects 阶段中,同步执行了useLayoutEffect 的上一次销毁函数,在 commitLayoutEffects 阶段中,同步执行了 useLayoutEffect 本次的执行函数,并注册上销毁函数。

    结论

    至此,我们粗略地查看了 commit 阶段的代码,分析了以下为什么 useEffect 是异步执行,而 useLayoutEffect 是同步执行,具体的代码我没有太过在文章中贴出来,因为这些都是可变的,真正的流程性的概览和 React 团队设计这一套机制的心智模型需要我们自己在不断调试代码和理解中慢慢去熟悉。

    后续自己感兴趣的是 hooks 的实现,其中比较关键的 useReducer 会着重看一下源码,看看能不能写个简易版本的放到支付宝小程序中去实现一个 自定义的支付宝hooks 用于日常生产力开发。


    起源地下载网 » useEffect 与 useLayoutEffect的区别

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元