如何在 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 请求
  };
}, []);
这种方式不仅避免状态更新问题,还能真正终止网络请求,节省资源。

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