React的useLayoutEffect

100 阅读2分钟

引言

在React中,useEffect 和 useLayoutEffect 是两个非常关键的Hook,用于处理组件的副作用(side effects)。尽管它们在很多方面相似,但它们在执行时机和执行方式上却有着本质的区别。

useLayoutEffect 的基础

使用方式

useLayoutEffect 接收一个函数和一个依赖项数组作为参数。这个函数会在组件的渲染阶段同步执行,即在浏览器绘制屏幕之前执行,从而有机会在DOM更新之前对DOM进行操作或读取最新的DOM状态。如果依赖项数组中的任何值发生变化,useLayoutEffect中的函数会重新执行。

返回值

useEffect一样,useLayoutEffect也可以返回一个清理函数,该函数会在组件卸载或依赖项变化导致的重新渲染之前执行,用于清理副作用。

useLayoutEffect 与 useEffect 的区别

执行时机

  • useEffect:在浏览器完成DOM更新后异步执行,不会阻塞浏览器绘制过程。
  • useLayoutEffect:在浏览器绘制DOM之前同步执行,会阻塞浏览器的绘制过程。

场景应用

  • useEffect:适用于大多数副作用操作,如数据获取、订阅或手动更改DOM(这些操作不需要在DOM更新前完成)。
  • useLayoutEffect:适用于需要在DOM更新前同步读取DOM尺寸或进行DOM操作的场景,如调整滚动位置、焦点管理等。

实际案例

场景:避免DOM闪烁

假设我们有一个组件,它显示一个数字,并允许用户点击按钮将数字重置为0。然而,如果重置后的逻辑处理(如将数字改为一个随机数)在DOM更新后执行,用户可能会看到数字从0瞬间变为另一个随机数,导致界面闪烁。

import React, { useState, useEffect, useLayoutEffect } from 'react';  
  
function RandomNumber() {  
  const [num, setNum] = useState(Math.random() * 200);  
  
  // 使用 useEffect 时,界面会闪烁  
  // useEffect(() => {  
  //   if (num === 0) {  
  //     setNum(10 + Math.random() * 200);  
  //   }  
  // }, [num]);  
  
  // 使用 useLayoutEffect 避免闪烁  
  useLayoutEffect(() => {  
    if (num === 0) {  
      setNum(10 + Math.random() * 200);  
    }  
  }, [num]);  
  
  return (  
    <>  
      <h1>num 的值是: {num}</h1>  
      <button onClick={() => setNum(0)}>重置num</button>  
    </>  
  );  
}  
  
export default RandomNumber;