如何正确清理包含异步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
相关产品推荐
相关产品推荐

