如何在 React 中正确地处理 useEffect 中的异步函数以避免内存泄漏?
如何在 React 中正确地处理 useEffect 中的异步函数以避免内存泄漏?
在 React 的 useEffect 中直接使用 async/await 会导致语法错误,因为 useEffect 的回调函数必须是同步的。如果在组件卸载后仍尝试更新状态,还会引发内存泄漏警告。正确做法是:
- 在 useEffect 内部定义一个异步函数,然后立即调用它;
- 使用清理函数(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)。

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