shfshanyue / Daily-Question

互联网大厂内推及大厂面经整理,并且每天一道面试题推送。每天五分钟,半年大厂中
https://q.shanyue.tech
4.95k stars 510 forks source link

【Q474】在 react 中,以下父子组件的 useEffect/useLayoutEffect 顺序如何 #802

Open shfshanyue opened 1 year ago

shfshanyue commented 1 year ago

以下代码在控制台里如何按序输出,代码见 codesandbox

import { useEffect, useLayoutEffect } from "react";
import "./App.css";

function Child() {
  console.log("Child: Render");

  useEffect(() => {
    console.log("Child: useEffect");
  });

  useLayoutEffect(() => {
    console.log("Child: useLayoutEffect");
  });

  return <div className="App">Child</div>;
}

function App() {
  console.log("App: render");

  useEffect(() => {
    console.log("App: useEffect");
  });

  useLayoutEffect(() => {
    console.log("App: useLayoutEffect");
  });

  return (
    <div className="App">
      App
      <Child />
    </div>
  );
}

export default App;
wangfengyuan commented 1 year ago

不太会,跑了下,运行结果如下 https://stackblitz.com/edit/vitejs-vite-ibcjhf?file=src%2FApp.jsx

App: render
Child: Render
Child: useLayoutEffect
App: useLayoutEffect
Child: useEffect
App: useEffect

学习了下面两篇文章: https://jser.dev/2023-07-08-how-does-useeffect-work https://jser.dev/react/2021/12/04/how-does-useLayoutEffect-work

总结一下我的理解: 1、useEffect 通过 scheduleCallback调度的,是异步执行的,也就是在渲染到页面后执行 而useLayoutEffect 是同步执行的,发生在dom mutation更新了dom结构,但是还未绘制到屏幕之前 2、useEffect 和 useLayoutEffect 都是递归执行的,先执行子组件 3、有useEffect 和 useLayoutEffect的fiber会被打上标记,加入到effectList中, 每次更新都会都会处理, 两个函数都会处理成effectObject, 包含create、destory属性,其中create是useEffect 和 useLayoutEffect传入的函数,destory对应传入的函数执行返回的函数,在commit阶段,每次都是先执行destory清理函数,然后执行create, 挂载时destory为undefined,跳过清理函数执行,执行create,执行后把return的函数复制给destory, 下一次更新时destory不为undefined就会执行destory销毁函数,如果dep有变化接下来执行create