「React」useEffect 与 useLayoutEffect 使用与区别

前言

useEffect 与 useLayoutEffect 是两个 Hooks,前者比较常用,后者在一些场景下也会用到,下面说明两者区别和应用场景。

使用

useEffectuseLayoutEffect 是React Hooks里用于处理副作用的钩子(Hooks),它们看起来非常相似,但实际上在何时执行副作用上有细微差别,这影响到了它们的使用场景。

useEffect

useEffect 是在组件渲染到屏幕之后异步执行的。这意味着它不会阻塞浏览器的绘制过程,可以用于大多数副作用场景,比如数据获取、订阅或者手动修改DOM当组件更新后等。

  • 使用场景: 用于大部分没有严格的执行时序要求的副作用操作。
  • 执行时机: 在全部DOM变更完成后,浏览器绘制之后异步执行。
  • 影响: 因为是异步执行,不会阻塞页面的可视化渲染。

useLayoutEffect

useLayoutEffect 的执行时机更接近于类组件的 componentDidMountcomponentDidUpdate 生命周期方法。它在DOM更新完成后同步执行,但在浏览器进行绘制前。

  • 使用场景 : 适用于需要同步调整布局的副作用操作。如果需要在DOM变化后立即同步执行一些操作(比如读取DOM布局并同步重绘),就可以用 useLayoutEffect
  • 执行时机: 在所有DOM变更之后同步执行,但在浏览器绘制之前。
  • 影响: 因为阻塞了浏览器的绘制,如果执行复杂或长时间运算,可能会导致性能问题或视觉上的卡顿。

区别

  • 执行时机 : useEffect 是异步执行,不会阻塞浏览器的绘制;而 useLayoutEffect 是同步执行,在所有DOM变更之后立即运行,但这会延迟浏览器的绘制。
  • 适用场景 : 一般推荐默认使用 useEffect,只有在涉及到需要在布局渲染阶段同步执行的DOM操作或有严格的顺序要求时,才使用 useLayoutEffect

由于 useLayoutEffect 会在绘制前执行,如果操作耗时过长,可能会导致用户感觉到卡顿。因此,除非必要,否则建议优先使用 useEffect

例子

当然可以。这里我会演示一个简单的例子,其中useLayoutEffectuseEffect将有不同的效果。

考虑以下场景:我们有一个要隐藏的消息,并且有一个按钮用于显示这个消息。如果我们使用useLayoutEffect去更改消息状态,用户界面不会显示任何隐藏-再显示的过渡效果,因为所有的更改都是在浏览器绘制之前发生的。相反,如果我们使用useEffect,那么可能会短暂看到消息从隐藏状态变为显示状态的过渡,因为useEffect是在组件渲染和浏览器绘制完成后才执行。

useLayoutEffect的行为

jsx 复制代码
import React, { useLayoutEffect, useState } from 'react';

function LayoutEffectDemo() {
  const [message, setMessage] = useState('这是一条消息');
  const [hidden, setHidden] = useState(true);

  useLayoutEffect(() => {
    if (hidden) {
      setMessage('这是一条消息');
    }
  }, [hidden]);

  return (
    <div>
      {!hidden && <p>{message}</p>}
      <button onClick={() => setHidden(false)}>显示信息</button>
    </div>
  );
}

在这个例子中,"这是一条消息"将会在按钮点击后立即正确显示,用户不会看到任何视觉变化之前消息的状态。

useEffect的行为

现在,我们用相同的例子但用useEffect来替代useLayoutEffect

jsx 复制代码
import React, { useEffect, useState } from 'react';

function EffectDemo() {
  const [message, setMessage] = useState('');
  const [hidden, setHidden] = useState(true);

  useEffect(() => {
    if (hidden) {
      setMessage('这是一条消息');
    }
  }, [hidden]);

  return (
    <div>
      {!hidden && <p>{message}</p>}
      <button onClick={() => setHidden(false)}>显示信息</button>
    </div>
  );
}

在使用useEffect的版本中,按钮点击后状态更新会导致组件的一个渲染周期,在这个周期中消息是隐藏的。然后useEffect会在这个渲染周期之后运行,并且消息会变成可见的。这个过程虽然非常快,但理论上可以被用户观察到,这就是为什么有的时候你会看到界面闪烁。

每一个钩子都有其用例,而显示不必要的用户界面变化(闪烁等)是应该避免的,通常是通过useLayoutEffect来处理,因为它在所有DOM变动之后同步执行,而且在浏览器进行绘制之前,从而保证用户看不到中间状态。

相关推荐
人生の三重奏1 分钟前
前端——js补充
开发语言·前端·javascript
Tandy12356_13 分钟前
js逆向——webpack实战案例(一)
前端·javascript·安全·webpack
TonyH200216 分钟前
webpack 4 的 30 个步骤构建 react 开发环境
前端·css·react.js·webpack·postcss·打包
你会发光哎u20 分钟前
Webpack模式-Resolve-本地服务器
服务器·前端·webpack
王小二(海阔天空)20 分钟前
个人文章合集 - 前端相关
前端·css·vue·jquery
老华带你飞29 分钟前
公寓管理系统|SprinBoot+vue夕阳红公寓管理系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·spring boot·课程设计
gopher95111 小时前
HTML详解
前端·html
Tiny20171 小时前
前端模块化CommonJs、ESM、AMD总结
前端
吕永强1 小时前
CSS相关属性和显示模式
前端·css·css3
结衣结衣.1 小时前
python中的函数介绍
java·c语言·开发语言·前端·笔记·python·学习