React useLayoutEffect
import * as React from 'react'
import { useState, useEffect, useLayoutEffect} from 'react'
import { createRoot } from 'react-dom/client'
function App() {
console.log('App')
const [state, setState] = useState(0)
useEffect(() => {
setState(state => state + 1)
}, [])
useEffect(() => {
console.log('useEffect 1')
return () => {
console.log('useEffect 1 cleanup')
}
}, [state])
useEffect(() => {
console.log('useEffect 2')
return () => {
console.log('useEffect 2 cleanup')
}
}, [state])
useLayoutEffect(() => {
console.log('useLayoutEffect')
return () => {
console.log('useLayoutEffect cleanup')
}
}, [state])
return null
}
const root = createRoot(document.getElementById('root'));
root.render(<App/>)
console:
“App”
“useLayoutEffect” // useLayoutEffect先于useEffect执行
“useEffect 1”
“useEffect 2”
“App”
“useLayoutEffect cleanup” // useLayoutEffect 首先被清理并立即执行
“useLayoutEffect”
“useEffect 1 cleanup” // useEffects 被分组、清理,然后执行
“useEffect 2 cleanup”
“useEffect 1”
“useEffect 2”
useEffect 和 useLayoutEffect 的区别?
useEffect 在渲染时是异步执行,并且要等到浏览器将所有变化渲染到屏幕后才会被执行。useLayoutEffect 在渲染时是同步执行,其执行时机与 componentDidMount,componentDidUpdate 一致
对于 useEffect 和 useLayoutEffect 哪一个与 componentDidMount,componentDidUpdate 的是等价的?
useLayoutEffect,因为从源码中调用的位置来看,useLayoutEffect的 create 函数的调用位置、时机都和 componentDidMount,componentDidUpdate 一致,且都是被 React 同步调用,都会阻塞浏览器渲染。
useEffect 和 useLayoutEffect 哪一个与 componentWillUnmount 的是等价的?
同上,useLayoutEffect 的 detroy 函数的调用位置、时机与 componentWillUnmount 一致,且都是同步调用。useEffect 的 detroy 函数从调用时机上来看,更像是 componentDidUnmount (注意React 中并没有这个生命周期函数)。
为什么建议将修改 DOM 的操作里放到 useLayoutEffect 里,而不是 useEffect?
- useLayoutEffect 能够阻塞浏览器重新绘制 ,在浏览器重新绘制屏幕之前触发。
- React内存中的 DOM 被修改后,此时浏览器渲染线程依旧处于被阻塞阶段,还没有发生回流、重绘过程,通过 useLayoutEffect可以拿到最新的 DOM 节点,并且在此时对 DOM 进行样式上的修改,假设修改了元素的 height,只会发生一次回流、重绘的。
- 如果放在 useEffect 里,useEffect 的函数会在组件渲染到屏幕之后执行,此时对 DOM
进行修改,会触发浏览器再次进行回流、重绘,增加了性能上的损耗。