useLayoutEffect 和 useEffect 区别、使用场景

useEffectuseLayoutEffect 都是 React 的副作用 Hook,但它们最大的区别是:

执行时机不同。


一句话理解

  • useEffect

    👉 页面渲染完成后异步执行(不阻塞页面绘制)

  • useLayoutEffect

    👉 DOM 更新后、浏览器绘制前同步执行(会阻塞页面绘制)


React 渲染流程理解

React 更新页面大致流程:

复制代码
1. React render
2. 更新 DOM
3. useLayoutEffect 执行
4. 浏览器绘制页面(paint)
5. useEffect 执行

所以:

复制代码
useLayoutEffect 更早
useEffect 更晚

图解理解

useEffect

复制代码
useEffect(() => {
  console.log('effect')
}, [])

流程:

复制代码
DOM更新
↓
页面先显示
↓
effect执行

用户会先看到页面。


useLayoutEffect

复制代码
useLayoutEffect(() => {
  console.log('layout effect')
}, [])

流程:

复制代码
DOM更新
↓
layout effect执行
↓
页面显示

effect 执行完页面才显示。


核心区别(面试重点)

对比 useEffect useLayoutEffect
执行时机 浏览器绘制后 浏览器绘制前
是否阻塞渲染 不阻塞 阻塞
执行方式 异步 同步
是否可能造成卡顿 不容易 容易
推荐程度 默认优先使用 特殊场景再用

使用场景


一、useEffect(99%场景)

这是最常用的。

适合:

  • 请求接口

  • 订阅事件

  • 定时器

  • localStorage

  • 数据获取

  • websocket

  • 日志埋点

示例:

复制代码
useEffect(() => {
  fetchUser()
}, [])

或者:

复制代码
useEffect(() => {
  const timer = setInterval(() => {
    console.log('timer')
  }, 1000)

  return () => clearInterval(timer)
}, [])

二、useLayoutEffect(操作 DOM)

只有当你:

"必须在页面绘制前修改 DOM"

才用它。

典型场景:


1. 获取 DOM 尺寸

因为此时 DOM 已更新。

复制代码
useLayoutEffect(() => {
  const width = divRef.current.offsetWidth
  console.log(width)
}, [])

2. 防止页面闪烁(非常经典)

例如:

复制代码
useEffect(() => {
  div.style.left = '100px'
}, [])

会发生:

复制代码
先显示原位置
再瞬移

用户能看到闪动。

而:

复制代码
useLayoutEffect(() => {
  div.style.left = '100px'
}, [])

浏览器绘制前就改好了。

用户看不到闪动。


3. 动画初始化

例如:

  • GSAP

  • Framer Motion

  • 拖拽库

  • 虚拟列表

很多库内部都用 useLayoutEffect


4. 同步测量 + 修改 DOM

经典:

复制代码
useLayoutEffect(() => {
  const height = ref.current.offsetHeight

  ref.current.style.height = height + 100 + 'px'
}, [])

因为:

复制代码
测量DOM
+
修改DOM

必须同步完成。


为什么不要乱用 useLayoutEffect

因为它会:

复制代码
阻塞浏览器绘制

如果里面:

  • 请求接口

  • 大计算

  • 循环

  • await

都会导致:

复制代码
白屏
卡顿
掉帧

所以 React 官方建议:

优先使用 useEffect。

只有"必须同步操作 DOM"才使用 useLayoutEffect


一个经典面试题


useLayoutEffect 会不会阻塞页面渲染?

会。

因为:

复制代码
它在浏览器 paint 前同步执行

所以会阻塞绘制。


useEffect 会不会?

不会。

因为:

复制代码
页面已经绘制完了

它是异步调度。


React18 注意点

在 React18 严格模式下:

复制代码
<React.StrictMode>

开发环境会:

复制代码
执行两次 effect

包括:

  • useEffect

  • useLayoutEffect

这是为了检查副作用是否安全。

生产环境不会。


服务端渲染 SSR 注意

useLayoutEffect 在 SSR 中会警告:

复制代码
useLayoutEffect does nothing on the server

因为:

复制代码
服务端没有 DOM

很多库会写:

复制代码
const useIsomorphicLayoutEffect =
  typeof window !== 'undefined'
    ? useLayoutEffect
    : useEffect

避免 SSR 报警告。


最佳实践(非常重要)

默认:

复制代码
useEffect

只有:

复制代码
需要同步操作DOM

才使用:

复制代码
useLayoutEffect

面试总结版(背诵)

useEffectuseLayoutEffect 都用于处理副作用。

区别是:

  • useEffect 在页面绘制后异步执行,不阻塞渲染,适合请求接口、订阅事件等普通副作用。

  • useLayoutEffect 在 DOM 更新后、浏览器绘制前同步执行,会阻塞页面渲染,适合 DOM 测量、同步修改 DOM、防止闪烁等场景。

开发中应优先使用 useEffect,只有需要同步操作 DOM 时才使用 useLayoutEffect

相关推荐
世界哪有真情10 分钟前
拿人类意识卡 AI?等于用 bug 验收正式产品
前端·人工智能·后端
:-)22 分钟前
算法-归并排序
java·开发语言·数据结构·算法·排序算法
鱼樱前端28 分钟前
别再自己拼凑了!这款 Vue 3.5+ 严肃产品级组件库,把 AI 对话、工作流和复杂数据全包了!
javascript·vue.js·github
Listen·Rain1 小时前
Vue3:setup详解
前端·javascript·vue.js
GIS阵地1 小时前
QgsRasterDataProvider 完整详解(QGIS 3.40.13 C++)
开发语言·c++·qt·开源软件·qgis
Patrick_Wilson2 小时前
修好 bug 只是开始:一次由监控需求反向重构日志结构的复盘
前端·监控·数据可视化
yaoxin5211232 小时前
462. Java 反射 - 获取声明类与封闭类
java·开发语言·python
kyriewen2 小时前
面试官让我优化一个卡死的表格,我打开 Claude 五秒重写,他放下咖啡问我要不要来当组长
前端·javascript·面试
阿里嘎多学长2 小时前
2026-07-14 GitHub 热点项目精选
开发语言·程序员·github·代码托管
小粉粉hhh3 小时前
React(二)——dom、组件间通信、useEffect
前端·javascript·react.js