useEffect和useLayoutEffect的区别是什么
useEffect和useLayoutEffect都是 React 提供的用于处理副作用的 Hooks,它们的 API 完全相同,但执行时机不同,这直接影响了它们的使用场景。
一、核心区别
执行时机
useEffect
- 在浏览器完成渲染之后异步执行
- 不会阻塞浏览器绘制
- 执行顺序:组件渲染 → 浏览器绘制 →
useEffect执行
useLayoutEffect
- 在 DOM 更新完成后、浏览器绘制之前同步执行
- 会阻塞浏览器绘制
- 执行顺序:组件渲染 →
useLayoutEffect执行 → 浏览器绘制
图解执行流程
Loading diagram...
二、使用场景
使用 useEffect 的场景(常见)
- 数据请求
- 事件监听器的添加/移除
- 订阅外部数据源
- 日志记录
- 大多数不需要同步执行的副作用
useEffect(() => {
// 数据请求
fetch('/api/data')
.then(res => res.json())
.then(setData);
// 事件监听
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);使用 useLayoutEffect 的场景(特殊)
- 需要读取 DOM 布局信息并立即进行样式更新
- 避免视觉闪烁的场景
- 需要在浏览器绘制前同步修改 DOM
三、实际案例对比
案例 1:tooltip 定位
使用 useEffect 会闪烁
使用 useLayoutEffect 无闪烁
案例 2:滚动位置恢复
四、性能考虑
💡
优先使用 useEffect
除非遇到视觉问题(闪烁、跳动),否则应该使用 useEffect,因为它不会阻塞浏览器渲染,用户体验更好。
useLayoutEffect 的性能影响
- 同步执行会阻塞页面渲染
- 如果回调函数执行时间长,会导致页面卡顿
- 应该尽量保持回调函数简短
五、服务端渲染(SSR)注意事项
useLayoutEffect 在服务端不会执行,但会产生警告。如果需要兼容 SSR:
六、选择决策树
Loading diagram...
七、常见误区
❌ 误区 1:所有 DOM 操作都用 useLayoutEffect
// 不必要,这个不会造成闪烁
useLayoutEffect(() => {
document.title = '新标题';
}, []);应该用 useEffect,因为修改 document.title 不会造成视觉问题。
❌ 误区 2:用 useLayoutEffect 来"加速"渲染
useLayoutEffect 会阻塞渲染,不会让页面更快,反而可能更慢。
八、总结
| 特性 | useEffect | useLayoutEffect |
| 执行时机 | 渲染后异步执行 | 渲染后、绘制前同步执行 |
| 是否阻塞渲染 | 否 | 是 |
| 使用频率 | 高(90%+ 的场景) | 低(特殊场景) |
| 性能影响 | 小 | 可能较大 |
| SSR 兼容性 | 好 | 需要特殊处理 |
| 典型场景 | 数据请求、事件监听 | DOM 测量、避免闪烁 |
🎯
最佳实践:默认使用
useEffect,只有当遇到闪烁、跳动等视觉问题时,才考虑使用 useLayoutEffect。