在Expo v35.0.0的React Native中如何取消异步Fetch请求?
Can't use AbortController in Expo v35.0.0? How to cancel async requests to avoid state update warnings?
问题根源
你遇到的AbortController is unknown错误是因为Expo v35.0.0对应的React Native版本是0.59.x,而AbortController是在React Native 0.60版本才正式引入的,所以你的当前环境并不支持这个API。
至于组件卸载后出现的Can't perform a React state update on an unmounted component警告,确实是因为异步请求还在进行时组件已经被卸载,后续的setIsLoading/setHasError尝试更新已卸载组件的状态导致的。
解决方案
我们分两种场景来解决这个问题:
1. 升级Expo版本(推荐,若项目允许)
如果你的项目没有强依赖Expo v35的特性,建议升级到Expo v36.0.0及以上版本(对应React Native 0.60+),这样就能原生支持AbortController了。
升级后,你可以这样修改代码来实现请求取消:
const loadData = async (id, token, abortController) => { setIsLoading(true); try { // 将signal传入fetch请求(假设fetchData内部使用了fetch API) await dispatch(fetchData(id, token, abortController.signal)); } catch (error) { // 排除取消请求的错误 if (error.name !== 'AbortError') { setHasError(true); } } setIsLoading(false); }; useEffect(() => { const abortController = new AbortController(); loadData(user.client.id, user.token, abortController); // 组件卸载时取消请求 return () => abortController.abort(); }, [user.client.id]);
注意:需要确保你的fetchData函数内部在调用fetch时传入了signal参数,比如:
const fetchData = (id, token, signal) => async (dispatch) => { const response = await fetch(`your-api-url/${id}`, { method: 'GET', headers: { Authorization: `Bearer ${token}` }, signal // 传入signal }); // 后续处理逻辑... };
2. 在Expo v35下的替代方案
如果无法升级Expo版本,我们可以用以下两种方式避免状态更新警告:
方案A:使用组件挂载状态标记
在组件内维护一个isMounted状态,在组件卸载时标记为false,异步操作完成后先检查该标记再执行状态更新:
const [isMounted, setIsMounted] = useState(true); useEffect(() => { return () => setIsMounted(false); // 组件卸载时标记为false }, []); const loadData = async (id, token) => { setIsLoading(true); try { await dispatch(fetchData(id, token)); } catch (error) { if (isMounted) { // 检查组件是否仍挂载 setHasError(true); } } if (isMounted) { // 检查组件是否仍挂载 setIsLoading(false); } }; useEffect(() => { if (isMounted) { loadData(user.client.id, user.token); } }, [user.client.id, isMounted]);
方案B:使用axios的CancelToken取消请求
如果你的项目可以切换到axios发起请求,axios提供了CancelToken机制来取消请求,这在React Native 0.59环境下是可行的:
首先安装axios:
expo install axios
然后修改代码:
import axios from 'axios'; const loadData = async (id, token, cancelToken) => { setIsLoading(true); try { await dispatch(fetchData(id, token, cancelToken)); } catch (error) { // 排除取消请求的错误 if (!axios.isCancel(error)) { setHasError(true); } } setIsLoading(false); }; useEffect(() => { const source = axios.CancelToken.source(); loadData(user.client.id, user.token, source.token); // 组件卸载时取消请求 return () => source.cancel('Component unmounted, canceling request'); }, [user.client.id]);
对应的fetchData函数修改为:
const fetchData = (id, token, cancelToken) => async (dispatch) => { const response = await axios.get(`your-api-url/${id}`, { headers: { Authorization: `Bearer ${token}` }, cancelToken // 传入CancelToken }); // 后续处理逻辑... };
总结
- 若能升级Expo版本,优先使用原生的AbortController方案,这是最标准的现代异步请求取消方式。
- 若无法升级,使用组件挂载标记或axios的CancelToken都能有效避免状态更新警告和潜在的内存泄漏。
内容的提问来源于stack exchange,提问作者Sheixt
相关产品推荐
相关产品推荐

