如何在 React 中正确地处理 useEffect 中的异步函数以避免内存泄漏?

如何在 React 中正确地处理 useEffect 中的异步函数以避免内存泄漏?

在 React 的 useEffect 中直接使用 async/await 会导致语法错误,因为 useEffect 的回调函数必须是同步的。如果在组件卸载后仍尝试更新状态,还会引发内存泄漏警告。正确做法是:

  1. 在 useEffect 内部定义一个异步函数,然后立即调用它;
  2. 使用清理函数(return 函数)配合一个 abort 标志或 AbortController 来取消未完成的异步操作。

示例代码:

import { useEffect, useState } from 'react';

function MyComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    let isMounted = true; // 防止组件卸载后 setState

    const fetchData = async () => {
      try {
        const response = await fetch('/api/data');
        const result = await response.json();
        if (isMounted) {
          setData(result);
        }
      } catch (error) {
        if (isMounted) {
          console.error('Fetch error:', error);
        }
      }
    };

    fetchData();

    return () => {
      isMounted = false; // 组件卸载时设置标志
    };
  }, []);

  return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
}

更现代的方式(推荐)是使用 AbortController:

useEffect(() => {
  const controller = new AbortController();

  const fetchData = async () => {
    try {
      const response = await fetch('/api/data', { signal: controller.signal });
      const result = await response.json();
      setData(result);
    } catch (error) {
      if (error.name !== 'AbortError') {
        console.error('Fetch error:', error);
      }
    }
  };

  fetchData();

  return () => {
    controller.abort(); // 自动取消 fetch 请求
  };
}, []);

解析:

  • useEffect 不能直接使用 async,因为其返回值应为函数(清理函数)或 undefined,而 async 函数返回 Promise;
  • 若不处理组件卸载后的状态更新,React 会警告“Can't perform a React state update on an unmounted component”;
  • 使用 isMounted 标志或 AbortController 是防止内存泄漏和无效状态更新的两种常见策略,后者更适合原生支持取消的 API(如 fetch)。

发表评论 (审核通过后显示评论):

昵称:
邮箱:
内容: