一、对于 useLayoutEffect
的形容
Reactjs 文档里这样形容useLayoutEffect
:
-
The signature is identical to
useEffect
, but it fires synchronously after all DOM mutations -
only 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
到底有什么区别?