创见博客
React之useLayoutEffect与useEffect
七崽爱吃小饼干2026/01/06阅读 1专栏 React

一、核心定义与作用

useLayoutEffect 是 React 提供的一个副作用 Hook,它的核心作用是在 DOM 更新之后、浏览器绘制(paint)之前 同步执行副作用代码。

可以把它理解为:React 先更新了 DOM 结构,还没来得及把更新后的界面画到屏幕上,就先执行 useLayoutEffect 里的代码,执行完后再让浏览器渲染画面。这个过程是同步阻塞的,会等代码执行完才继续绘制。

它的语法和 useEffect 完全一致:

jsx
import { useLayoutEffect, useState } from 'react';

function MyComponent() {
  const [width, setWidth] = useState(0);

  useLayoutEffect(() => {
    // 副作用代码:读取/修改 DOM 样式、计算 DOM 尺寸等
    const div = document.getElementById('my-div');
    if (div) {
      setWidth(div.offsetWidth); // 同步获取 DOM 尺寸
    }

    // 清理函数(可选)
    return () => {
      // 组件卸载/依赖变化时执行
    };
  }, []); // 依赖数组(和 useEffect 规则一致)

  return <div id="my-div">宽度:{width}</div>;
}

二、与 useEffect 的核心区别(关键)

这是理解 useLayoutEffect 的核心,两者的差异主要在执行时机和阻塞性:

特性useEffectuseLayoutEffect
执行时机DOM 更新后 → 浏览器绘制后执行DOM 更新后 → 浏览器绘制前执行
执行方式异步执行(不阻塞浏览器绘制)同步执行(阻塞浏览器绘制)
视觉体验可能出现“闪屏”(先绘制约错样式,再修正)无闪屏(绘制前修正样式,用户看不到中间态)
适用场景数据请求、订阅、非 DOM 相关副作用读取/修改 DOM 布局、同步调整样式

直观示例:对比两者的执行效果

jsx
import { useEffect, useLayoutEffect, useState } from 'react';

function LayoutEffectDemo() {
  const [color, setColor] = useState('red');

  // useEffect:绘制后执行,会先看到红色,再闪成蓝色
  // useEffect(() => {
  //   setColor('blue');
  // }, []);

  // useLayoutEffect:绘制前执行,直接看到蓝色,无闪屏
  useLayoutEffect(() => {
    setColor('blue');
  }, []);

  return <div style={{ width: 100, height: 100, backgroundColor: color }}></div>;
}

三、适用场景

只有当你需要同步读取/修改 DOM 布局,且不想让用户看到中间态时,才需要用 useLayoutEffect,常见场景:

  1. 计算 DOM 尺寸/位置:比如获取元素的 offsetWidth、scrollTop,同步更新状态(避免 useEffect 导致的“先渲染错的尺寸,再修正”);
  2. 调整 DOM 样式:比如根据元素位置动态设置定位、避免页面闪烁;
  3. 同步操作 DOM:比如在 DOM 更新后立即修改元素的属性,确保用户看不到过渡状态。

四、使用注意事项

  1. 避免耗时操作:useLayoutEffect 是同步阻塞的,里面的代码如果耗时(比如循环、复杂计算),会直接卡住浏览器,导致页面加载/交互卡顿。耗时逻辑请放到 useEffect 或 Web Worker 中;
  2. 服务端渲染 (SSR) 注意:在服务端渲染时,useLayoutEffect 不会执行(因为服务端没有 DOM 绘制),如果代码依赖它,可能导致客户端和服务端渲染不一致。解决方法:要么改用 useEffect,要么加判断(比如 typeof window !== 'undefined');
  3. 依赖数组规则:和 useEffect 完全一致,依赖数组为空则只执行一次(组件挂载后),依赖变化时重新执行,清理函数在组件卸载/依赖变化前执行;
  4. 优先用 useEffect:大部分场景下 useEffect 足够用,且不会阻塞渲染,只有确需同步操作 DOM 布局时,才用 useLayoutEffect。

总结

  1. useLayoutEffect 执行时机是 DOM 更新后、浏览器绘制前,同步阻塞,无视觉闪屏;useEffect 是绘制后异步执行,可能有闪屏;
  2. 核心用途是同步读取/修改 DOM 布局(如计算尺寸、调整样式),避免用户看到中间态;
  3. 慎用耗时操作,优先用 useEffect,仅在需要同步操作 DOM 布局时使用 useLayoutEffect。
评论
0/100