useLayoutEffect
是 React 中的一个 Hook,用于处理需要在浏览器绘制前同步执行的副作用操作。它与 useEffect
功能相似,但执行时机不同,适用于需要避免视觉闪烁或直接操作 DOM 的场景。以下是详细解析:
1. 核心特性
- 同步执行:在浏览器绘制(Paint)前同步触发,阻塞页面渲染直至副作用完成。
- 适用场景:DOM 尺寸/布局测量、强制同步样式更新等需要与浏览器渲染周期同步的操作。
- 与
useEffect
对比:useEffect
:异步执行,在渲染完成后延迟触发(不阻塞绘制)。useLayoutEffect
:同步执行,在 DOM 更新后、绘制前立即触发。
2. 基本语法
useLayoutEffect(() => {
// 副作用逻辑(如 DOM 操作)
return () => {
// 清理逻辑(可选)
};
}, [dependencies]);
- 参数:与
useEffect
完全一致,包括依赖项数组。 - 返回值:可选的清理函数(类似
componentWillUnmount
)。
3. 执行时机详解
React 的渲染流程分为几个阶段:
- Render 阶段:生成虚拟 DOM,计算变更。
- Commit 阶段:
- Before Mutation:DOM 操作前。
- Mutation:执行 DOM 更新。
- Layout:DOM 更新后,浏览器绘制前。
useLayoutEffect
在此阶段同步执行。
- Paint 阶段:浏览器绘制页面。
4. 典型使用场景
避免视觉闪烁
useLayoutEffect(() => {
const element = document.getElementById('tooltip');
if (element) {
element.style.left = '100px'; // 同步调整位置,避免闪烁
}
}, [tooltipVisible]);
测量 DOM 元素
useLayoutEffect(() => {
const rect = ref.current.getBoundingClientRect();
setSize({ width: rect.width, height: rect.height });
}, []);
5. 注意事项
- 性能风险:同步执行可能阻塞渲染,导致卡顿。避免耗时操作(如复杂计算或大量数据请求)。
- 服务端渲染(SSR):
useLayoutEffect
在服务端会触发警告(因无 DOM),需替换为useEffect
或条件调用。 - 依赖项管理:与
useEffect
相同,需精确声明依赖以避免无限循环。
6. 与 useEffect
的对比示例
特性 | useLayoutEffect |
useEffect |
---|---|---|
执行时机 | DOM 更新后,绘制前(同步) | 绘制后(异步) |
适用操作 | DOM 测量、同步样式调整 | 数据获取、订阅事件 |
性能影响 | 可能阻塞渲染 | 不阻塞渲染 |
总结
useLayoutEffect
是 React 为特殊场景提供的高精度控制工具,适合需要与浏览器渲染同步的 DOM 操作。多数情况下优先使用 useEffect
,仅在视觉一致性要求严格时切换为 useLayoutEffect
。