认识React Hooks: useLayoutEffect

104 阅读2分钟

在React中,useLayoutEffect 是一个与 useEffect 类似的 Hook,但它们在执行时机上有所不同。useLayoutEffect 的调用是在所有DOM变更之后,浏览器绘制之前同步执行的。这意味着你可以使用它来读取或修改DOM,而不会造成可见的闪烁。useEffect 则是在浏览器绘制之后异步执行的,通常用于数据获取、订阅或其他不需要立即反映在DOM上的操作。

从源码层面来看,useLayoutEffect 和 useEffect 都是通过调度更新来工作的。但是,useLayoutEffect 会在所有DOM变更之后立即同步调用,而 useEffect 会在浏览器完成绘制后延迟调用。这就是为什么 useLayoutEffect 更适合处理DOM测量和同步更新的原因。

以下是 useLayoutEffect 的一个简单示例,展示了如何在组件渲染后同步测量DOM节点的尺寸:

import { useLayoutEffect, useRef, useState } from 'react';

function MyComponent() {
  const ref = useRef(null);
  const [height, setHeight] = useState(0);

  useLayoutEffect(() => {
    setHeight(ref.current.clientHeight);
  }, []);

  return (
    <div ref={ref}>
      {/* ... */}
    </div>
  );
}

在这个示例中,useLayoutEffect 用于在组件渲染到屏幕后立即测量 div 元素的高度,并在状态中保存这个值。由于 useLayoutEffect 在浏览器绘制之前执行,用户不会看到任何闪烁或布局变化。

执行时机:

useLayoutEffect 在DOM更新完成后,浏览器绘制之前同步执行。这意味着可以在浏览器绘制前读取或修改DOM,避免出现闪烁。 useEffect 在DOM更新后,浏览器绘制之后的下一个宏任务中执行。通常用于不需要立即反映在DOM上的操作,如数据请求。

用途:

useLayoutEffect 适用于需要同步执行的操作,特别是那些对布局有影响的DOM操作,如测量布局大小。 useEffect 适用于不需要立即反映在DOM上的副作用,如API调用、设置订阅等。

服务端渲染(SSR):

在SSR中,useLayoutEffect 不会执行,因为它依赖于浏览器环境。如果在SSR中使用,可能会导致客户端和服务端内容不一致。 useEffect 在SSR中也不会执行,但由于它通常用于不影响DOM的操作,所以不会导致不一致问题。

总的来说,useLayoutEffect 应该在需要同步执行副作用操作,特别是那些涉及DOM测量和可能影响布局的操作时使用。如果副作用与DOM无关,或者不需要同步执行,那么 useEffect 是更好的选择。在服务端渲染(SSR)中,由于 useLayoutEffect 不会执行,可能会导致客户端和服务端渲染的内容不一致,因此在SSR中应避免使用 useLayoutEffect,或者使用条件判断来替换为 useEffect