React 浏览器重新绘制之前副作用之useLayoutEffect

介绍

  • useLayoutEffect 是 useEffect 的一个版本,在浏览器重新绘制屏幕之前触发。

语法

tsx 复制代码
useLayoutEffect(setup, dependencies?)

参数

  • setup:处理副作用的函数。setup 函数选择性返回一个清理(cleanup)函数。在将组件首次添加到 DOM 之前,React 将运行 setup 函数。在每次因为依赖项变更而重新渲染后,React 将首先使用旧值运行 cleanup 函数(如果你提供了该函数),然后使用新值运行 setup 函数。在组件从 DOM 中移除之前,React 将最后一次运行 cleanup 函数。

  • 可选 dependencies:setup 代码中引用的所有响应式值的列表。响应式值包括 props、state 以及所有直接在组件内部声明的变量和函数。如果你的代码检查工具 配置了 React,那么它将验证每个响应式值都被正确地指定为一个依赖项。依赖项列表必须具有固定数量的项,并且必须像 [dep1, dep2, dep3] 。如果省略此参数,则在每次重新渲染组件之后,将重新运行副作用函数。

tsx 复制代码
mport { useState, useRef, useLayoutEffect } from 'react';

function Tooltip() {
  const ref = useRef(null);
  const [tooltipHeight, setTooltipHeight] = useState(0); // 还不知道真正的高度

  useLayoutEffect(() => {
    const { height } = ref.current.getBoundingClientRect();
    setTooltipHeight(height); // 现在重新渲染,你知道了真实的高度
  }, []);

  return (
    <div ref={ref} style={{ height: tooltipHeight }}>
      Tooltip content
      </div>
  );

useEffect VS useLayoutEffect

hooks名称 执行时机 执行过程
useEffect 在浏览器重新绘制屏幕之后触发 异步执行,不阻塞浏览器绘制
useLayoutEffect 在浏览器重新绘制屏幕之前触发 同步执行,阻塞浏览器重新绘制

示例

点击按钮,把 num 值设置为 0,当页面更新完成后,判断 num 是否等于 0,如果等于 0,则在 useEffect 中把 num 赋值为随机的数字:

tsx 复制代码
export const RandomNumber: React.FC = () => {
  const [num, setNum] = useState(Math.random() * 200)

  useEffect(() => {
    if (num === 0) {
      setNum(10 + Math.random() * 200)
    }
  }, [num])

  return (
    <>
      <h1>num 的值是:{num}</h1>
      <button onClick={() => setNum(0)}>重置 num</button>
    </>
  )
}

运行上面的代码,会出现闪烁的情况。原因是页面会先将 h1 渲染为 0,然后再渲染成随机的数字,由于更新的很快便出现了闪烁。

为了解决上述问题,可以把 useEffect 替换为 useLayoutEffect:

jsx 复制代码
export const RandomNumber: React.FC = () => {
  const [num, setNum] = useState(Math.random() * 200)

  useLayoutEffect(() => {
    if (num === 0) {
      setNum(10 + Math.random() * 200)
    }
  }, [num])

  return (
    <>
      <h1>num 的值是:{num}</h1>
      <button onClick={() => setNum(0)}>重置 num</button>
    </>
  )
}

更改完成后,数字不再闪烁了。因为点击按钮时,num 更新为 0,但此时页面不会渲染,而是等待 useLayoutEffect 内部状态修改后才会更新页面,所以不会出现闪烁。

注意事项

  1. useLayoutEffect 内部的代码和所有计划的状态更新阻塞了浏览器重新绘制屏幕。如果过度使用,这会使你的应用程序变慢。如果可能的话,尽量选择 useEffect。
  2. useLayoutEffect 是一个 Hook,因此只能在 组件的顶层 或自己的 Hook 中调用它。不能在循环或者条件内部调用它。
相关推荐
狗头大军之江苏分军5 小时前
告别旧生态:Ant Design 6 不再支持 IE 与现代前端趋势解读
前端·javascript·后端
C_心欲无痕5 小时前
nginx - 开启 gzip 压缩
运维·前端·nginx
闲云一鹤5 小时前
2026 最新 ComfyUI 教程 - 本地部署 AI 生图模型 - Z-Image-Turbo
前端·人工智能·ai编程
开开心心_Every5 小时前
安卓后台录像APP:息屏录存片段,行车用
java·服务器·前端·学习·eclipse·edge·powerpoint
狗头大军之江苏分军5 小时前
Ant Design 6.0 正式发布:从 V5 到 V6 有哪些变化?
前端
优弧5 小时前
Claude 终于对普通人下手了!Cowork 发布,你的最强 AI 打工搭子来了!
前端·后端
Zoey的笔记本6 小时前
敏捷与稳定并行:Scrum看板+BPM工具选型指南
大数据·前端·数据库·python·低代码
Captaincc6 小时前
如何在一天内重启你的人生
程序员
文心快码BaiduComate6 小时前
0代码手写!体验百度Comate的“魔法”:我造了个会理解情绪的中介层
前端·程序员·前端框架
Captaincc6 小时前
Vibe Coding 进阶:非技术人员的生存手册
程序员·vibecoding