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