一、关于useLayoutEffect
的描述
Reactjs文档里这样描述useLayoutEffect
:
The signature is identical to
useEffect
, but it fires synchronously after all DOM mutationsonly differs in when it is fired
即useLayoutEffect
跟useEffect
函数签名一致,但是在DOM修改后同步触发,这是和useEffect
唯一的区别。
二、何时使用useLayoutEffect
?
假设有个展示随机数字的case,当count
为0时随机生成个数字:
2.1 先使用useEffect
实现:
import { useState, useEffect, useLayoutEffect } from 'react'
export default function App() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`useEffect - count=${count}`)
// 耗时的操作
const pre = Date.now();
while(Date.now() - pre < 500) {}
// count为0时重新生成个随机数
if (count === 0) {
setCount(10 + Math.random() * 200);
}
}, [count]);
// 点击DIV重置count
return (
<div onClick={() => setCount(0)}>{count}</div>
);
}
可以看到展示0的过程。
2.2 改用useLayoutEffect
实现:
import { useState, useEffect, useLayoutEffect } from 'react'
export default function App() {
const [count, setCount] = useState(0);
useLayoutEffect(() => {
console.log(`useLayoutEffect - count=${count}`)
// 耗时的操作
const pre = Date.now();
while(Date.now() - pre < 500) {}
if (count === 0) {
setCount(10 + Math.random() * 200);
}
}, [count]);
return (
<div onClick={() => setCount(0)}>{count}</div>
);
}
-
没有闪烁,当点击 div,count 更新为 0,此时页面并不会渲染,而是等待
useLayoutEffect
内部状态修改后,才会去更新页面,所以页面不会闪烁。Updates scheduled inside
useLayoutEffect
will be flushed synchronously, before the browser has a chance to paint - 但是也可以发现页面更新的比较卡顿,因为
useLayoutEffect
会阻塞浏览器渲染,正好本例中useLayoutEffect
的实参函数里有个耗时操作,所以页面更新比较卡顿。
2.3 useLayoutEffect
和componentDidMount
、componentDidUpdate
触发时机一致
上面的例子改用class
组件实现试试:
import React from 'react'
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
}
}
componentDidUpdate() {
// 耗时的操作
const pre = Date.now();
while(Date.now() - pre < 500) {}
}
increaseCount = () => {
this.setState(({ count }) => {
return { count: count + 1}
})
}
render() {
const { count } = this.state;
return (
<div onClick={this.increaseCount}>{count}</div>
)
}
}
跟useLayoutEffect
效果一样:也是看不到闪烁,但也比较卡顿。
2.4 综上:
-
useLayoutEffect
和componentDidMount
和componentDidUpdate
触发时机一致(都在在DOM修改后且浏览器渲染之前); -
useLayoutEffect
要比useEffect
更早的触发执行; -
useLayoutEffect
会阻塞浏览器渲染,切记执行同步的耗时操作。
三、小结:
除非要修改DOM并且不让用户看到修改DOM的过程,才考虑使用useLayoutEffect
,否则应当使用useEffect
。
注意:如果只是为了获取DOM属性(或其它get操作),则没必要使用useLayoutEffect
,应当使用useEffect
。
四、参考:
整理自gitHub笔记useEffect
和useLayoutEffect
到底有什么区别?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。