如何在 React 中正确地处理异步副作用以避免内存泄漏?

如何在 React 中正确地处理异步副作用以避免内存泄漏?

回答与解析:

在 React 中,使用 useEffect 处理异步操作(如数据获取)时,若组件在异步任务完成前卸载,可能会导致对已卸载组件的状态进行更新,从而引发内存泄漏警告或运行时错误。

正确做法: 使用“取消标记”(cleanup function)来跟踪组件的挂载状态。

import { useState, useEffect } from 'react';

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

  useEffect(() => {
    let isMounted = true; // 标记组件是否仍挂载

    const fetchData = async () => {
      const result = await fetch('/api/data');
      const json = await result.json();
      if (isMounted) {
        setData(json); // 仅在组件仍挂载时更新状态
      }
    };

    fetchData();

    // 清理函数:组件卸载时设置标记为 false
    return () => {
      isMounted = false;
    };
  }, []);

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

原理说明:

  • useEffect 的返回函数会在组件卸载(或依赖变化时重新执行 effect 前)被调用。
  • 通过 isMounted 标志,确保 setState 只在组件仍处于挂载状态时执行。
  • 这种模式虽然不是真正的“取消”请求(fetch 本身无法中断,除非使用 AbortController),但能防止对已卸载组件的状态更新。

更优方案(推荐): 使用 AbortController 取消请求:

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

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

  fetchData();

  return () => {
    controller.abort(); // 取消正在进行的 fetch 请求
  };
}, []);

这种方式不仅避免状态更新问题,还能真正终止网络请求,节省资源。

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

昵称:
邮箱:
内容: