乐趣区

关于react.js:面试官useLayoutEffect和useEffect的区别

面试官:useLayoutEffect 和 useEffect 的区别

hello,这里是潇晨,大家面试的过程中有没有遇到过这样的问题呢,useLayoutEffect 和 useEffect 的区别是什么,大家可能会答复 useEffect 是异步的,useLayoutEffect 是同步的,这样答复面试官真的会称心慢,咱们须要说分明他们在源码中的调用机会。

先来看个例子:点击触发更新之后,如果 count 之前的状态是 0,咱们随机生成一个数字,在阻塞一段时间,在设置 count 位随机值,看看在 useEffect 和 useLayoutEffect 这两种状况下会有什么不同

import React, {useLayoutEffect, useState, useEffect} from "react";

export default function App() {const [count, setCount] = useState(0);
  
  // 用 useLayoutEffect 试试
  useEffect(() => {if (count === 0) {const randomNum = Math.random() * 100;// 随机生成一个数字

      const now = performance.now();

      while (performance.now() - now < 100) {// 阻塞一段时间
        console.log('blocking...');
      }

      setCount(randomNum);// 从新设置状态,设置成随机数
    }
  }, [count]);

  return <div onClick={() => setCount(0)}>{count}</div>;
}

// 在 useEffect 的状况下,一直点击触发更新,偶然会显示 0
// 在 useLayoutEffect 的状况下,一直点击触发更新,不会偶现 0 

在源码中不论首次渲染还是更新的时候都会经验一个阶段叫 commit 阶段,这个阶段次要的工作就是解决一些钩子函数、生命周期、遍历 render 阶段造成的 EffectList 链表,将带有副作用的 Fiber 节点利用到实在节点上,如果对 render 阶段不理解能够参阅往期文章 render 阶段,上面这张图是 commit 阶段源码的结构图,咱们具体的解说一下。

在 commitRootImpl 的函数中次要分三个局部:

  • commit 阶段前置工作
  • mutation 阶段

    1. 调用 commitBeforeMutationEffects,scheduleCallback 调度执行 flushPassiveEffects
    2. 调用 commitMutationEffects,解决相干的副作用,操作实在节点 useLayoutEffect 的销毁函数在这个函数中执行
    3. 调用 commitLayoutEffects,调用 commitLayoutEffects 的回调函数,这个时候副作用曾经利用到实在节点了,所以能拿到最新的节点。
    4. 在 commit 阶段完结之后 flushPassiveEffects 执行 useEffect 的销毁函数和回调函数。
  • commit 阶段收尾工作

所以 useLayout/componentDidMount 和 useEffect 的区别是什么?

答:他们在 commit 阶段不同机会执行,useEffect 在 commit 阶段结尾异步调用,useLayout/componentDidMount 同步调用

具体源码调试视频(高效学习): 点击学习

往期 react 源码解析文章:

1. 开篇介绍和面试题

2.react 的设计理念

3.react 源码架构

4. 源码目录构造和调试

5.jsx& 外围 api

6.legacy 和 concurrent 模式入口函数

7.Fiber 架构

8.render 阶段

9.diff 算法

10.commit 阶段

11. 生命周期

12. 状态更新流程

13.hooks 源码

14. 手写 hooks

15.scheduler&Lane

16.concurrent 模式

17.context

18 事件零碎

19. 手写迷你版 react

20. 总结 & 第一章的面试题解答

退出移动版