You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确清理包含异步GraphQL操作的React useEffect

问题:React+GraphQL/Apollo依赖更新后AbortError导致catch块频繁触发

我使用GraphQL/Apollo和React开发,更新依赖包后,原有useEffect代码出现错误:Uncaught (in promise) DOMException: signal is aborted without reason。这个错误会在组件卸载、依赖变更且异步查询未完成时触发,导致catch块频繁执行。我临时通过判断AbortError后不更新状态来规避,但想了解正确的处理方式。

原有代码

const [state, setState] = useState(undefined);
useEffect(() => {
  (async () => {
    try {
      const workspace = await getFirstWorkspace();
      // Do Something
      setState(withSomething)
    } catch (error) {
      // Do Something Else
      setState(withErrorSomething)
    }
  })();
}, [generateLink, getFirstWorkspace, masterDataStoreId]);

临时修复代码

const [state, setState] = useState(undefined);
useEffect(() => {
  (async () => {
    try {
      const workspace = await getFirstWorkspace();
      // Do Something
      setState(withSomething)
    } catch (error) {
      // Do Something Else
      if ((error as any)?.name === 'AbortError') {
        return;
      }
      setState(withErrorSomething)
    }
  })();
}, [generateLink, getFirstWorkspace, masterDataStoreId]);

正确处理方式

这个错误是新版本Apollo Client的默认行为:当组件卸载或依赖变更时,会自动中止未完成的请求(通过AbortController),目的是避免在已卸载组件上更新状态引发内存泄漏。你的临时修复方向是对的,以下是更规范的实现:

1. 关联AbortSignal并规范错误捕获

利用浏览器原生的AbortController,手动关联请求信号,同时更精准地捕获AbortError:

const [state, setState] = useState(undefined);
useEffect(() => {
  const abortController = new AbortController();
  const { signal } = abortController;

  (async () => {
    try {
      // 若getFirstWorkspace支持传入signal参数,直接传递(Apollo生成的查询函数通常支持)
      const workspace = await getFirstWorkspace({ signal });
      // 确保请求未被中止、组件仍挂载时再更新状态
      if (!signal.aborted) {
        setState(withSomething);
      }
    } catch (error) {
      // 精准判断AbortError,无需any断言
      if (error instanceof DOMException && error.name === 'AbortError') {
        return; // 请求被主动中止,无需处理
      }
      // 处理业务逻辑错误
      setState(withErrorSomething);
    }
  })();

  // 组件卸载/依赖变更时,主动中止请求
  return () => abortController.abort();
}, [generateLink, getFirstWorkspace, masterDataStoreId]);

2. 关键细节说明

  • 如果getFirstWorkspace是Apollo Client生成的手动查询函数(比如client.query()),它本身就支持接收signal参数,传递后Apollo会自动处理请求中止逻辑
  • 检查signal.aborted是额外的安全层:避免请求刚好完成但组件已卸载的极端场景下更新状态
  • 仅跳过AbortError,其他业务错误(比如网络失败、GraphQL查询错误)仍需正常处理

内容的提问来源于stack exchange,提问作者Crocsx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 00:35:29