useEffect条件渲染异常:isMobile为true时仍触发Fetch请求
解决React useEffect在isMobile为true时仍触发数据请求的问题
可能的问题根源
- 初始isMobile状态不准确:如果
useWindowSize钩子的初始状态是硬编码的默认值(比如false),而非直接计算当前窗口宽度,会导致组件初始渲染时isMobile为false,触发请求后才更新为true,最终出现请求已发送的情况。 - 闭包导致的状态捕获问题:若
getData函数定义在useEffect外部,可能捕获到旧的isMobile值,导致内部的判断逻辑失效。
具体解决方案
1. 修正useWindowSize的初始状态
确保useWindowSize在组件挂载时就直接计算当前窗口宽度,而非依赖resize事件更新:
function useWindowSize() { const [isMobile, setIsMobile] = useState(() => { // 初始渲染时直接计算窗口尺寸,兼容服务端渲染场景 return typeof window !== 'undefined' ? window.innerWidth < 992 : false; }); useEffect(() => { const handleResize = () => { setIsMobile(window.innerWidth < 992); }; window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); return isMobile; }
2. 在useEffect内直接前置判断逻辑
把isMobile的判断放在useEffect最开头,直接终止执行,避免进入请求逻辑:
useEffect(() => { // 不符合条件立即返回,跳过请求逻辑 if (isMobile) return; const fetchData = async () => { const data = await fetchClientApi(); setState(data); }; fetchData(); }, [isMobile]);
3. 添加请求取消机制(可选)
如果担心初始状态仍有延迟导致请求发出,可以用AbortController取消未完成的请求,避免无效数据更新:
useEffect(() => { const controller = new AbortController(); const signal = controller.signal; if (isMobile) { controller.abort(); return; } const fetchData = async () => { try { // 将signal传入请求方法,支持请求取消 const data = await fetchClientApi({ signal }); setState(data); } catch (error) { // 忽略取消请求的错误,只处理其他异常 if (error.name !== 'AbortError') { console.error('请求失败:', error); } } }; fetchData(); // 组件卸载或依赖更新时自动取消请求 return () => controller.abort(); }, [isMobile]);
内容的提问来源于stack exchange,提问作者Vladimir
相关产品推荐
相关产品推荐

