React严格模式下useEffect异步调用报DOMException错误求助
解决React严格模式下useEffect异步GraphQL请求的DOMException错误
这个问题本质是React 18严格模式在开发环境下的特殊行为导致的:它会模拟组件「挂载-卸载-重新挂载」的过程,用来检测未清理的副作用。当useEffect因为依赖变化重新执行时,旧的异步请求还未完成,React会自动中止该请求的AbortSignal,如果你的代码没处理这个信号,就会抛出DOMException: signal is aborted without reason错误。
解决方案:给异步请求添加中止信号处理
需要两步修改:给GraphQL请求传入AbortSignal,并在useEffect的清理函数中主动中止未完成的请求。
1. 修改useEffect代码,添加AbortController
useEffect(() => { const controller = new AbortController(); const signal = controller.signal; const loadTags = async () => { try { // 把signal传给fetchTags const { data } = await fetchTags(signal); // 确保请求未被中止时再更新状态,避免过时的状态变更 if (!signal.aborted) { setTags([...(data?.tags || [])]); } } catch (err) { // 忽略AbortError,这是清理时的预期行为 if (err.name !== 'AbortError') { console.error('标签加载失败:', err); } } }; loadTags(); // 组件卸载或useEffect重新执行时,中止请求 return () => controller.abort(); }, [current, fetchTags]);
2. 更新fetchTags函数,支持AbortSignal
以Apollo Client为例,需要在请求上下文传入signal:
// 假设fetchTags是基于Apollo Client封装的查询函数 const fetchTags = async (signal) => { return await client.query({ query: YOUR_TAGS_GRAPHQL_QUERY, context: { signal }, // 将中止信号传入请求 }); };
说明
- 这个错误不是依赖包的问题,而是React 18严格模式的新行为暴露了代码中未处理请求中止的问题。
- 生产环境下严格模式的双重执行逻辑会被关闭,但添加中止信号处理依然是最佳实践,能避免组件卸载后更新状态导致的内存泄漏。
内容的提问来源于stack exchange,提问作者Crocsx
相关产品推荐
相关产品推荐

