返回

理解 useEffect 和 useLayoutEffect 的执行时机

前端

在 React 的世界中,useEffect 和 useLayoutEffect 是两个重要的 Hooks,用于处理组件的生命周期和副作用。虽然它们在结构和功能上非常相似,但它们在事件循环中的调用时机却截然不同。

useEffect

useEffect 的回调函数是【异步宏任务】,将在下一轮事件循环中执行。这意味着在当前事件循环中,useEffect 的回调函数不会立即执行,而是会被推迟到下一轮事件循环中。这使得 useEffect 非常适合处理那些不依赖于当前渲染结果的副作用,例如网络请求、设置定时器或订阅事件。

useLayoutEffect

useLayoutEffect 的回调函数是【同步微任务】,将在本轮事件循环中执行,并且早于 DOM 更新。这意味着在当前事件循环中,useLayoutEffect 的回调函数将在 DOM 更新之前执行。这使得 useLayoutEffect 非常适合处理那些依赖于当前渲染结果的副作用,例如更新 DOM 元素的大小或位置。

为了更清晰地理解 useEffect 和 useLayoutEffect 的执行时机,我们来看一个简单的示例。假设我们有一个 React 组件,需要在每次渲染后更新其高度。如果我们使用 useEffect 来处理这个副作用,则该组件的高度将在下一轮事件循环中更新。这意味着在当前事件循环中,组件的高度不会立即更新,而是在下一轮事件循环中才更新。这可能会导致组件在一段时间内呈现不正确的高度。

import React, { useEffect } from 'react';

const MyComponent = () => {
  useEffect(() => {
    const element = document.getElementById('my-element');
    element.style.height = '100px';
  }, []);

  return <div id="my-element"></div>;
};

export default MyComponent;

如果我们使用 useLayoutEffect 来处理这个副作用,则该组件的高度将在本轮事件循环中更新,并且早于 DOM 更新。这意味着在当前事件循环中,组件的高度将立即更新,不会出现不正确的高度。

import React, { useLayoutEffect } from 'react';

const MyComponent = () => {
  useLayoutEffect(() => {
    const element = document.getElementById('my-element');
    element.style.height = '100px';
  }, []);

  return <div id="my-element"></div>;
};

export default MyComponent;

总的来说,useEffect 和 useLayoutEffect 都非常有用,但它们适用于不同的场景。useEffect 适用于处理那些不依赖于当前渲染结果的副作用,而 useLayoutEffect 适用于处理那些依赖于当前渲染结果的副作用。通过理解它们在事件循环中的不同之处,您可以更好地选择合适的 Hooks 来构建高效、响应迅速的 React 应用。