useEffect和useLayoutEffect有什么区别?

在React里,useEffectuseLayoutEffect这对兄弟Hook都能让你处理副作用,比如操作DOM、发起请求。它们长得像,但执行的时机有微妙而重要的区别。用错了,可能会导致页面闪烁或者性能问题。

关键区别:执行时机不同

想象一下浏览器渲染一帧的过程:React计算好组件变化(渲染)-> 浏览器把变化画到屏幕上(绘制)。useEffectuseLayoutEffect就卡在这个流程的不同节点上。

useEffect异步的。React会在浏览器完成本次绘制(把像素点画到屏幕上)之后,才去执行useEffect里的回调函数。你可以把它理解成一个“事后诸葛亮”,等页面看起来已经稳定了,它再悄悄跑你的副作用代码。

useEffect(() => {
  // 这里改DOM,用户可能会先看到旧状态,再看到闪烁的变化
  document.title = `新标题`;
});

useLayoutEffect同步的。它的执行时机要早得多,发生在React计算出DOM变动之后,但浏览器真正着手绘制之前。它会阻塞浏览器的绘制。

useLayoutEffect(() => {
  // 这里改DOM,浏览器绘制前就改好了,用户看不到中间状态
  someRef.current.style.transform = 'translateX(100px)';
});

这带来了什么实际影响?

最直接的感受是,如果你在useEffect里直接修改DOM的样式或布局(比如改变一个元素的高度、位置),用户可能会先看到元素在旧位置闪现一下(浏览器绘制了旧状态),然后才跳到新位置(你的副作用生效了)。这就是恼人的布局闪烁。

useLayoutEffect能帮你避免这个闪烁。因为它在浏览器动笔之前就把DOM改好了,用户看到的就是最终效果。听起来useLayoutEffect更厉害?别急,它有代价:因为它阻塞绘制,如果里面的逻辑很耗时,就会让用户觉得页面卡住了

怎么选?记住这个原则

日常开发中,默认永远用useEffect。它能满足99%的场景:数据获取、订阅、手动修改React管理的DOM(通过ref)等等。让浏览器先流畅地画出来,副作用慢点跑没关系。

只有当你需要直接、同步地操作DOM的样式或布局,并且需要避免用户看到视觉闪烁时,才换用useLayoutEffect。典型的例子是:测量DOM元素尺寸后立即调整其位置、基于DOM尺寸自动滚动到特定位置。

一个简单的比喻:useEffect像是等客人看完房间布置(绘制完成)后,你再进去调整家具。useLayoutEffect则是趁客人还没进门,你就火速把家具摆好。后者体验更无缝,但如果你搬家具太慢,客人就得在门口干等。

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容