被 50px 到 200px 的闪烁整破防了?useLayoutEffect 和 useEffect 的区别原来在这

写了个简单的布局:一个浅蓝色块默认高 50px,加载后要改成 200px 并居中。结果每次刷新都先看到矮块闪一下,再变成高块 ------ 明明就两行样式,咋就出了这种幺蛾子?

排查半天发现,罪魁祸首是我用错了钩子。今天就借着这个真实案例,聊聊 useEffect 和 useLayoutEffect 到底咋区分,以及为啥换个钩子就能解决闪烁问题。

先搞懂俩钩子到底啥时候干活?

不管是 useEffect 还是 useLayoutEffect,本质都是用来处理 "副作用" 的 ------ 比如操作 DOM、发请求、订阅事件这些。但它们干活的时间点,差了关键一步。

先简单说下 useEffect:它就像个 "慢性子",等页面渲染完、浏览器把内容画到屏幕上之后,才慢悠悠地执行。比如你改个 DOM 样式,它会等页面已经显示出来了再动手,所以有时候会看到 "先这样,再那样" 的跳变。

而 useLayoutEffect 是个 "急性子",它会在 DOM 更新完但还没画到屏幕上的时候就冲上去干活。相当于说:"等一下!先别画!让我改完这处再显示!" 所以它能保证你改的样式在屏幕上一次性到位,不会出现中间状态。

为啥会有 "闪烁"?用个案例说清楚

最典型的场景就是处理 DOM 样式的时候。比如你想让一个元素从 A 样式瞬间变成 B 样式,用不好就会闪一下。

我做了个简单的例子:

jsx 复制代码
import { 
  useEffect,
  useLayoutEffect,
  useRef
 } from 'react'

function Show(){
   const ref = useRef(null)
  useEffect(()=>{
    const heightPx = 200; // 明确使用数值
    ref.current.style.height = `${heightPx}px`;
    ref.current.style.marginTop = `${(window.innerHeight - heightPx) / 2}px`;
  },[])

   return (
    <div ref={ref} style={{height:'50px',background:'lightblue'}}>
      内容
    </div>
   )
}

当你在浏览器快速刷新页面的时候,会看到明显的残影,也就是所谓的'闪烁'

换成 useLayoutEffect 试试:

jsx 复制代码
// 阻塞渲染 同步的感觉
useLayoutEffect(()=>{
    const heightPx = 200; // 明确使用数值
    ref.current.style.height = `${heightPx}px`;
    ref.current.style.marginTop = `${(window.innerHeight - heightPx) / 2}px`;
},[])

这次无论怎么刷新,都不会出现'闪烁效果'!因为 useLayoutEffect 在浏览器把内容画到屏幕之前就改完了样式,相当于 "偷偷" 改好再展示,自然不会有中间状态。

核心区别就一句话

  • useEffect:渲染完 → 浏览器画到屏幕上 → 再执行(异步,不阻塞渲染)
  • useLayoutEffect:渲染完 → 改 DOM → 浏览器再画(同步,会阻塞渲染)

简单说,useLayoutEffect 是 "赶在显示前插队改样式",useEffect 是 "显示完了再慢慢改"。

啥时候用哪个?

大多数时候用 useEffect 就行,毕竟不阻塞渲染,性能更好。但如果遇到这些情况,就得请 useLayoutEffect 出场了:

  1. 操作 DOM 样式时出现闪烁(比如上面的例子)
  2. 需要 "同步" 拿到 DOM 更新后的状态(比如获取元素宽高后立即调整位置)

不过要注意,useLayoutEffect 里别写太耗时的代码,不然会卡住页面 ------ 它可是会等你执行完才让浏览器画画的。

最后再总结下:useEffect 是 "佛系处理",useLayoutEffect 是 "急着搞定"。记住它们干活的时间点,以后遇到样式闪烁的坑,就知道该找谁帮忙啦~ 你们平时用这俩钩子的时候,还遇到过啥有意思的问题?评论区交流下呗~

相关推荐
小雨青年5 分钟前
Cursor 项目实战:AI播客策划助手(四)—— 产品发布与交付收尾
前端·人工智能
晚霞的不甘21 分钟前
Flutter for OpenHarmony《淘淘购物》主页点击跳转功能详解:从 UI 响应到页面导航的完整实现
前端·flutter·ui·搜索引擎·前端框架·交互
cooldream200922 分钟前
前端技术架构详解:Vue 3 + TypeScript + Vite 在具身 AI 系统中的实践
前端·架构·typescript
迟_43 分钟前
CSS-实现图片靠右
前端·css
weixin_395448911 小时前
下位机&yolov11输出
java·服务器·前端
秋秋秋秋秋雨1 小时前
基于若依的vue3+springboot3基础架构项目,前端优化
前端
Dragon Wu1 小时前
Web前端 认证token的安全存储策略
前端·javascript·安全·react.js·前端框架
橙露1 小时前
各类 Shell 优劣势深度解析与实战选型指南
前端·chrome
广州华水科技1 小时前
单北斗GNSS在变形监测中的应用与发展探讨
前端
克里斯蒂亚诺更新1 小时前
vue2 单文件组件加入浏览器的title和ico的方法
前端·javascript·html