useEffect与useLayoutEffect
  
# useEffect过程
import { useState, useEffect } from 'react'
export default function App() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    // 耗时的操做
    const pre = Date.now();
    while(Date.now() - pre < 1000) {}
    // 异步操作
    getNewList()
    // count为0时从新生成个随机数
    if (count === 0) {
      setCount(10 + Math.random() * 200);
    }
  }, [count]);
  return (
      <button onClick={() => setCount(0)}>{count}</button>
  );
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 点击按钮,count更新,立即执行重新渲染操作,渲染出虚拟DOM,并与上次虚拟DOM做对比,生成最终的虚拟DOM =>
 - 浏览器将虚拟DOM渲染到页面(将过程是异步的,将该异步任务加入任务队列) =>
 - 检测是否有可执行的useEfffect,如果有,执行useEffect中的同步任务,然后将异步任务加入到任务队列 =>
 - 将浏览器渲染虚拟DOM的任务从任务队列取出并执行,完成后,浏览器就可以看到变化了 =>
 - 将useEffect中的异步任务取出执行
 
# useLayoutEffect过程
import { useState, useLayoutEffect } from 'react'
export default function App() {
  const [count, setCount] = useState(0);
  useLayoutEffect(() => {
    // 耗时的操做
    const pre = Date.now();
    while(Date.now() - pre < 1000) {}
    // 异步操作
    getNewList()
    // count为0时从新生成个随机数
    if (count === 0) {
      setCount(10 + Math.random() * 200);
    }
  }, [count]);
  return (
      <button onClick={() => setCount(0)}>{count}</button>
  );
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 点击按钮,count更新,立即渲染出虚拟DOM,并与上次虚拟DOM做对比,生成最终的虚拟DOM =>
 - 执行useLayoutEffect中的同步任务,然后将异步任务加入到任务队列 =>
 - 浏览器将虚拟DOM渲染到页面, 完成后,浏览器就可以看到变化了=>
 - 任务队列按优先级去执行useLayoutEffect中的异步任务
 
# 注意
1. 在useEffect、useLayoutEffect中遇到了setState
- 在useEffect 中调用 setState,会等待浏览器渲染完成,再去做 setState 操作,重新渲染虚拟dom。
 - 在useLayoutEffect中调用setState,react会立即更新组件,重新渲染虚拟DOM,上一次的浏览器渲染就不会执行了。
 
# 应用场景
useEffect内需要改变 Layout 布局时,用useLLayoutEffect,其他场景用useEffect
编辑  (opens new window)
  上次更新: 2023/02/16