React:useEffect和useLayoutEffect区别?
在React中,useEffect
和useLayoutEffect
是两个常用的钩子,它们用于在函数组件中处理副作用。这两个钩子有一些相似之处,但它们在执行时机和用途上有一些重要的区别。
useEffect
useEffect
是在组件渲染到屏幕之后执行的。它不会阻塞浏览器绘制,意味着页面更新完成后再执行useEffect
中的代码。
用途
- 数据获取:从API获取数据并更新组件状态。
- 订阅:设置订阅,如WebSocket连接或数据流订阅。
- 事件监听:添加或移除事件监听器。
- 清理副作用:在组件卸载或依赖变化时清理副作用。
示例
import React, { useState, useEffect } from 'react';
const ExampleComponent = () => {
const [data, setData] = useState(null);
useEffect(() => {
// 组件挂载后执行
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data));
// 清理函数在组件卸载时或依赖项变化时执行
return () => {
console.log('Cleaning up...');
};
}, []); // 依赖数组为空,只在组件挂载和卸载时执行
return (
<div>
{data ? <pre>{JSON.stringify(data, null, 2)}</pre> : 'Loading...'}
</div>
);
};
useLayoutEffect
useLayoutEffect
是在所有DOM变更之后同步执行的。这意味着它会在浏览器绘制之前执行,可能会阻塞页面渲染,直到其完成。
用途
- 读取DOM布局:读取DOM元素的布局信息,如尺寸和位置。
- 同步DOM变更:同步地处理副作用,以确保在浏览器绘制之前完成。
- 避免闪烁:在组件更新后立即执行操作,防止用户在屏幕上看到不一致的内容。
示例
import React, { useState, useRef, useLayoutEffect } from 'react';
const LayoutEffectComponent = () => {
const [height, setHeight] = useState(0);
const divRef = useRef(null);
useLayoutEffect(() => {
// 在浏览器绘制之前同步执行
if (divRef.current) {
setHeight(divRef.current.getBoundingClientRect().height);
}
}, [height]); // 当 height 变化时再次执行
return (
<div ref={divRef} style={{ height: `${height}px`, background: 'lightblue' }}>
The height of this div is: {height}px
</div>
);
};
区别总结
-
执行时机:
useEffect
:在组件渲染到屏幕之后异步执行,不会阻塞浏览器绘制。useLayoutEffect
:在所有DOM变更之后同步执行,会阻塞浏览器绘制,直到其完成。
-
用途:
useEffect
:用于异步操作(如数据获取、订阅、事件监听)和不影响布局的副作用。useLayoutEffect
:用于需要同步执行的操作(如读取DOM布局、同步DOM变更)和防止布局闪烁的副作用。
-
性能影响:
useEffect
:性能友好,因为它不会阻塞浏览器绘制。useLayoutEffect
:可能会影响性能,因为它会阻塞浏览器绘制,直到其完成。
何时使用
- 使用
useEffect
:大多数副作用处理应该使用useEffect
,因为它不会阻塞浏览器的绘制,并且通常不会影响用户体验。 - 使用
useLayoutEffect
:在需要同步处理DOM操作且必须在浏览器绘制之前完成的情况下使用useLayoutEffect
,例如读取布局信息或防止内容闪烁。
实践中的选择
在实践中,推荐默认使用useEffect
,只有在确实需要同步处理DOM并避免布局闪烁的情况下,才使用useLayoutEffect
。这有助于确保良好的性能和用户体验,同时减少不必要的复杂性和潜在的性能问题。
转载自:https://juejin.cn/post/7380994802744754213