高级前端react【Q474】在 react 中,以下父子组件的 useEffect/useLayoutEffect 顺序如何

在 react 中,以下父子组件的 useEffect/useLayoutEffect 顺序如何

更多描述 以下代码在控制台里如何按序输出,代码见 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;

Issue 欢迎在 Gtihub Issue 中回答此问题: Issue 802

Author 回答者: wangfengyuan

不太会,跑了下,运行结果如下 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