在 React 中,useEffect 和 useLayoutEffect 都是用于处理副作用的 Hook,但它们的执行时机不同,这导致了在更新状态时对渲染行为的影响也有所不同。本文将通过两个例子来展示它们之间的区别。
两个例子都是在render后再次更新state重新触发render,唯一差别是一个使用useEffect,而一个使用useLayoutEffect
使用useEffect
const Component = ({containerState}) => {
console.log('component rendered')
const [state, setState] = useState(1);
useEffect(() => {
console.log('component mounted')
return () => {
console.log('component unmounted')
}
}, [])
return <>
<h1>{state}</h1>
<button onClick={() => {
setState((state) => state + 1)
}}>state
</button>
</>
}
可以看到使用useEffect更新具有明显闪屏,从先绘制1,后更新重新绘制为2
使用useLayoutEffect
const Component = ({containerState}) => {
console.log('component rendered')
const [state, setState] = useState(1);
useLayoutEffect(() => {
console.log('layoutEffect mounted')
setState((state) => state + 1)
return () => {
console.log('layoutEffect unmounted')
}
}, []);
return <>
<h1>{state}</h1>
<button onClick={() => {
setState((state) => state + 1)
}}>state
</button>
</>
}
而使用useLayoutEffect更新state则直接绘制为2,因为useLayoutEffect执行在render函数执行之后,第一次绘制之前
生命周期图示
下图展示了 React 组件的生命周期,特别是 useEffect 和 useLayoutEffect 的执行时机:
总结
useEffect:适合大多数副作用场景,执行时机在渲染完成后异步执行,可能会导致页面闪烁。useLayoutEffect:适合需要在 DOM 更新后立即同步执行的场景,能够避免页面闪烁,但可能会阻塞渲染。