businessfragmentation

useLayoutEffect 是 React 中的一个 Hook,用于在浏览器重新绘制屏幕之前触发,与 useEffect 类似。

用法

import {useLayoutEffect} from 'react'
useLayoutEffect(() => {
  // 副作用代码
  return () => {
    // 清理代码
  }
}, [dependencies]);

参数

  • setup:Effect处理函数,可以返回一个清理函数。组件挂载时执行setup,依赖项更新时先执行cleanup再执行setup,组件卸载时执行cleanup。
  • dependencies(可选):setup中使用到的响应式值列表(props、state等)。必须以数组形式编写如 dep1, dep2 。不传则每次重渲染都执行Effect。

返回值

useLayoutEffect 返回 undefined

useEffect vs useLayoutEffect 对比

特性useEffectuseLayoutEffect
执行时机在浏览器 绘制完成后 异步执行(不阻塞渲染)在浏览器 绘制前 同步执行(会阻塞渲染)
执行阶段属于 渲染提交阶段后的副作用(Commit Phase 之后)属于 渲染提交阶段中的副作用(Commit Phase 中,DOM 更新后、绘制前)
对 DOM 修改的影响若修改 DOM,用户可能看到闪烁(先渲染旧状态,再更新)修改 DOM 时,用户看不到中间状态(更新在绘制前完成)
典型使用场景数据获取、订阅、手动 DOM 操作(无需即时反馈)需要同步读取/修改 DOM(如测量元素尺寸、调整布局、避免闪烁的动画)
类组件对应方法componentDidMount + componentDidUpdate + componentWillUnmountcomponentDidMount + componentDidUpdate(但执行时机更早)
性能影响异步执行,不阻塞渲染,适合大多数场景同步执行,可能阻塞渲染,过度使用会导致性能问题
// 使用 useEffect(可能看到闪烁)
useEffect(() => {
  const element = document.getElementById("my-element");
  if (element) element.style.height = "100px";
}, [deps]);

// 使用 useLayoutEffect(无闪烁)
useLayoutEffect(() => {
  const element = document.getElementById("my-element");
  if (element) element.style.height = "100px";
}, [deps]);

关键区别详解

执行时机

<font style="color:#000000;">useEffect</font>:在 React 完成 DOM 更新 并触发浏览器绘制后异步执行,用户会先看到更新后的界面,再执行副 作用(可能伴随二次渲染)。

<font style="color:#000000;">useLayoutEffect</font>:在 React 更新 DOM 但浏览器尚未绘制前同步执行,用户看到的界面已经是最终状态

适用场景

优先使用 **<font style="color:#000000;">useEffect</font>**:大多数副作用(如 API 请求、日志记录、非紧急 DOM 操作)。

必须使用 **<font style="color:#000000;">useLayoutEffect</font>**:当需要同步读取或修改 DOM(如测量元素尺寸、调整布局、避免视觉闪烁)。

// 示例:避免元素尺寸变化导致的闪烁
useLayoutEffect(() => {
  const element = document.getElementById("my-element");
  if (element) element.style.height = "100px";
}, [deps]);

性能开销

<font style="color:#000000;">useEffect</font>更高效,因为异步执行不会阻塞浏览器渲染流程。

<font style="color:#000000;">useLayoutEffect</font>可能导致性能瓶颈(同步执行阻塞渲染)导致浏览器渲染阻塞,需谨慎使用。

代码示例对比

场景:修改 DOM 元素尺寸

import React,{useEffect,useLayoutEffect} from 'react'
// 使用 useEffect(可能看到闪烁)
useEffect(() => {
  const element = document.getElementById("my-element");
  if (element) element.style.height = "100px";
}, [deps]);

// 使用 useLayoutEffect(无闪烁)
useLayoutEffect(() => {
  const element = document.getElementById("my-element");
  if (element) element.style.height = "100px";
}, [deps]);

总结

场景推荐 Hook
数据获取、订阅、非紧急操作useEffect
同步 DOM 读写、布局调整、防闪烁useLayoutEffect