useEffect&useLayoutEffect

最近在复习React hook相关用法知识,尝试优化当前项目上关于性能与展示优化的一些问题,需要重新回顾一下useEffectuseLayoutEffect的用法以及原理

什么是Effect

Effect 被翻译为 副作用, React 中的Effect 是一种用于处理副作用操作的机制,指的是操作那些与组件渲染无关的任务,例如:数据获取、订阅事件、手动操作DOM等。Effect能够在组件被挂载、更新或者卸载时执行、其目的是将这些操作与组件的逻辑分离,确保它们在正确的时间点被执行。

常见用途
  1. 数据获取
  2. 事件订阅
  3. 清理资源
  4. 状态变化监听
  5. ...
useEffect基础用法
javascript 复制代码
useEffect(setup, dependencies?)
javascript 复制代码
import { useEffect } from 'react';  

import { createConnection } from './chat.js';  

  
function ChatRoom({ roomId }) {  

	const [serverUrl, setServerUrl] = useState('https://localhost:1234');  

	useEffect(() => {  
	
		const connection = createConnection(serverUrl, roomId);  
		
		connection.connect();  
		
		return () => {  
		
			connection.disconnect();  
		
		};  
	
	}, [serverUrl, roomId]);  

// ...  

}

以官网的demo代码为例,setup为一个函数,里面的运行逻辑依赖第二个参数中的依赖列表[serverUrl, roomId] 其中依赖数据的变化会导致setup函数的运行,默认组件挂载时候也会执行一次。 依赖参数的填写需要注意,不写任何数据、空数组、有数据 的情况均反馈不同,不写任何依赖的情况下,每次触发组件渲染均会执行setup函数,而写空数组则之后在组件挂载时触发一次,而写了关系的依赖则会根据依赖数据的状态变化而判断是否需要执行。 注意:依赖参数慎用空值

setup函数可以返回一个cleanup函数,其执行点会在每次依赖项变化重新渲染后,React会将旧值运行cleanup函数,然后再使用新值执行setup函数,另外在组件销毁时,也会执行一次cleanup函数。 一般cleanup函数里面可以做一些timer、dom eventListener等的销毁解绑等操作。

useLayoutEffect基础用法

useEffectapi 用法一致。

javascript 复制代码
useLayoutEffect(setup, dependencies?)
两者差异

既然两者用法一样,为何会提供两个不一样的hook工具呢?

text 复制代码
- If your Effect wasn't caused by an interaction (like a click), React will generally let the browser **paint the updated screen first before running your Effect.** If your Effect is doing something visual (for example, positioning a tooltip), and the delay is noticeable (for example, it flickers), replace `useEffect` with [`useLayoutEffect`.](https://zh-hant.react.dev/reference/react/useLayoutEffect)
    
- If your Effect is caused by an interaction (like a click), **React may run your Effect before the browser paints the updated screen**. This ensures that the result of the Effect can be observed by the event system. Usually, this works as expected. However, if you must defer the work until after paint, such as an `alert()`, you can use `setTimeout`. See [reactwg/react-18/128](https://github.com/reactwg/react-18/discussions/128) for more information.
    
- Even if your Effect was caused by an interaction (like a click), **React may allow the browser to repaint the screen before processing the state updates inside your Effect.** Usually, this works as expected. However, if you must block the browser from repainting the screen, you need to replace `useEffect` with [`useLayoutEffect`.](https://zh-hant.react.dev/reference/react/useLayoutEffect)
    
The code inside useLayoutEffect and all state updates scheduled from it block the browser from repainting the screen.  When used excessively, this makes your app slow.  When possible, prefer useEffect.

从官网上查到此内容

其大概的意思是说 如果你的effect不是由交互(比如点击)引起的, React通常会让浏览器在运行你的effect之前先绘制更新的屏幕。如果你的effect是在做一些视觉上的事情(例如,定位工具提示),并且延迟是明显的(例如,它闪烁),用uselayouteeffect替换useEffect 如果您的Effect是由交互(如点击)引起的,React可能会在浏览器绘制更新的屏幕之前运行您的Effect。这确保了事件系统可以观察到Effect的结果。通常情况下,这是预期的。但是,如果您必须将工作延迟到绘制之后,例如alert(),则可以使用setTimeout。

即使你的Effect是由交互(比如点击)引起的,React也可能允许浏览器在处理你的Effect中的状态更新之前重新绘制屏幕。通常情况下,这是预期的。但是,如果您必须阻止浏览器重新绘制屏幕,则需要将useEffect替换为uselayouteeffect。

useLayoutEffect中的代码和从它调度的所有状态更新阻止浏览器重新绘制屏幕。当过度使用时,这会使你的应用变慢。如果可能的话,使用useEffect。

这表达的有点很模糊,总结一下

执行时机不同
  1. useEffect 在组件渲染到屏幕之后异步执行setup, 这意味着它不会阻塞浏览器的绘制和更新、适用于大多数与数据获取、订阅事件、手动修改DOM 等不会直接影响页面布局和视觉呈现的操作
  2. useLayoutEffect 会在浏览器进行布局和绘制之前同步执行。useLayoutEffect中执行操作会修改DOM样式和结构,并且在浏览器绘制之前就完成这些修改,避免页面的重绘和回流带来的性能问题。
渲染时机影响不同
  1. useEffect 的执行不会阻塞浏览器渲染工作
  2. useLayoutEffect 的执行可能会阻塞浏览器的渲染,需要注意性能问题,不要运行耗时过长的任务。
useEffect useLayoutEffect
触发时机 在浏览器绘制完成后 异步执行 在DOM更新后、浏览器绘制前同步执行
阻塞渲染 不会阻塞浏览器绘制 阻塞浏览器绘制直到回调完成
底层原理对比

React 渲染流程大致分为以下4点

  1. Render Phase (生成虚拟DOM)
  2. Commit Phase (更新真实DOM)
  3. Browser Paint (浏览器绘制页面)
  4. Effect Callbacks (执行UseEffect)
  • useLayoutEffect的回调在 Commit Phase 后立即执行(步骤2/3之间)
  • useEffect 的回调在 Browser Paint 后执行 (步骤3之后)
使用场景对比
适合useLayoutEffect的场景
  • 需要同步修改DOM 例如调整元素尺寸位置
  • 需要在浏览器回之前消除视觉闪烁(如快速切换状态导致的布局抖动)
  • 需要读取DOM布局信息 如滚动位置、元素尺寸
适合useEffect的场景
  • 数据获取
  • 事件监听
  • 日志记录
  • 大多数操作
相关推荐
当牛作馬3 小时前
React——ant-design组件库使用问题记录
前端·react.js·前端框架
hxmmm5 小时前
react合成事件
react.js
然我6 小时前
React 事件机制:从代码到原理,彻底搞懂合成事件的核心逻辑
前端·react.js·面试
光影少年7 小时前
react16-react19都更新哪些内容?
前端·react.js
小陈phd7 小时前
langchain从入门到精通(四十一)——基于ReACT架构的Agent智能体设计与实现
react.js·架构·langchain
16年上任的CTO7 小时前
一文讲清楚React中的key值作用与原理
前端·javascript·react.js·react key
幼年程序猿8 小时前
基于antd组件库,手写动态渲染表单项组件
react.js
FogLetter12 小时前
从原生JS事件到React事件机制:深入理解前端事件处理
前端·javascript·react.js
胡gh13 小时前
React组件实用,每个组件各司其职,成为信息管理大师
前端·react.js
sophie旭13 小时前
《深入浅出react》总结之 10.2 渲染阶段流程探秘-completeWork
前端·react.js·源码