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

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

回答:
在 React 的 useEffect 中直接使用 async/await 是不允许的,因为 useEffect 的回调函数必须是同步函数。正确的做法是在 useEffect 内部定义一个异步函数,然后立即调用它。同时,为了防止组件卸载后异步操作仍尝试更新状态(导致内存泄漏),应使用取消机制(如 AbortController 或布尔标志)。

示例代码:

import { useEffect, useState } from 'react';

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

  useEffect(() => {
    let isMounted = true; // 防止内存泄漏的标志

    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; // 清理阶段设置标志为 false
    };
  }, []);

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

解析:

  • useEffect 的回调不能是 async 函数,因为 React 期望它返回一个清理函数或 undefined,而 async 函数会返回 Promise。
  • 使用 isMounted 标志(或 AbortController 用于 fetch)可以确保组件卸载后不再执行状态更新,避免 “Can't perform a React state update on an unmounted component” 警告。
  • 在依赖数组为空([])时,effect 只在组件挂载时执行一次,清理函数在组件卸载时运行。
  • 对于更复杂的场景(如多个异步请求),建议使用 AbortController 来取消 fetch 请求,以释放资源。

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

昵称:
邮箱:
内容: