React Native中使用useCallback仍出现无限Fetch循环问题求助
React Native useFetch钩子无限循环问题排查与修复
问题现象
加载标签页时发起Fetch请求出现无限循环,日志反复打印~~ fetchData ~~和~~ fetchData - try ~~,请求后续的响应处理代码完全无法执行。
问题根源
无限循环的核心原因是**useCallback的依赖项不稳定**:
- 你在
TabTwoScreen中传入的body是空对象{},每次组件渲染时,空对象都会被重新创建(引用地址发生变化) useCallback会因为body的引用变化,重新生成fetchData函数useEffect的依赖是fetchData,每次fetchData更新就会触发effect执行,调用fetchData;而fetchData内的状态更新(setIsLoading/setApiData)又会触发组件重新渲染,进而再次创建新的空对象body,形成闭环无限循环
修复方案
方案1:稳定body的引用
如果是GET请求,本身不需要body参数,直接不传或传undefined即可,同时给useFetch设置参数默认值:
// 修改useFetch钩子的参数默认值 export const useFetch = (method: string, url: string, body: any = undefined) => { // ... 原有逻辑不变 }; // 在TabTwoScreen中调用 export default function TabTwoScreen() { const { isLoading, serverError, apiData } = useFetch( 'GET', 'https://jsonplaceholder.typicode.com/posts/1' ); }
如果确实需要传空对象,用useMemo稳定其引用:
import { useMemo } from 'react'; export default function TabTwoScreen() { const emptyBody = useMemo(() => ({}), []); const { isLoading, serverError, apiData } = useFetch( 'GET', 'https://jsonplaceholder.typicode.com/posts/1', emptyBody ); }
方案2:简化钩子逻辑,去掉不必要的useCallback
如果不需要对外暴露fetchData函数,直接把请求逻辑放在useEffect内部,避免依赖项管理的麻烦:
import axios from 'axios'; import { useState, useEffect } from 'react'; export const useFetch = (method: string, url: string, body: any) => { const [isLoading, setIsLoading] = useState(false); const [apiData, setApiData] = useState(null); const [serverError, setServerError] = useState(null); useEffect(() => { const fetchData = async () => { console.log('~~ fetchData ~~'); try { console.log('~~ fetchData - try ~~'); const res = await axios({ method: method, url: url, data: body, }); console.log('~~ fetchData - res ~~'); console.log(res); const data = res?.data; console.log('~~ setApiData - useState ~~'); console.log(`Data: ${data}`); setApiData(data); } catch (error: any | unknown) { setServerError(error); } finally { setIsLoading(false); } }; setIsLoading(true); fetchData(); }, [url, method, body]); return { isLoading, apiData, serverError }; };
额外优化建议
- 给请求加上中止逻辑,防止组件卸载时请求未完成导致内存泄漏:
useEffect(() => { const abortController = new AbortController(); const fetchData = async () => { try { const res = await axios({ method: method, url: url, data: body, signal: abortController.signal, // 关联中止信号 }); // ... 数据处理逻辑 } catch (error) { if (axios.isCancel(error)) return; // 忽略取消请求的错误 setServerError(error); } finally { setIsLoading(false); } }; setIsLoading(true); fetchData(); return () => abortController.abort(); // 组件卸载时中止请求 }, [url, method, body]);
内容的提问来源于stack exchange,提问作者cphill
相关产品推荐
相关产品推荐

