React Native中Fetch API请求结果不一致问题排查
Expo Go中Fetch API首次请求异常,热重载后恢复的问题排查与解决
问题描述
使用Expo Go测试React Native应用时,通过Fetch API抓取https://www.thesubath.com/whats-on/的HTML内容,首次加载出现异常:返回结果要么是带循环引用的对象{"next": null, "parent": {"children": [[Circular]], "endIndex": null, "next": null, "parent": null, "prev": null, "startIndex": null, "type": "root"}},要么是空对象{}。但按下Ctrl+S触发热重载后,就能正常获取完整的HTML数据。
原代码
import React, { useEffect, useState } from 'react' import { ActivityIndicator, StyleSheet, Text, useWindowDimensions, View } from 'react-native'; const EventsScreen = () => { const [eventsHTML, setEventsHTML] = useState({}); const {width} = useWindowDimensions(); const ParseEventsHTML = ()=>{ console.log(eventsHTML); } const RefreshEvents = ()=>{ console.log("refreshing events"); fetch('https://www.thesubath.com/whats-on/') .then(response => response.text()) .then(textResponse => { setEventsHTML(textResponse); ParseEventsHTML(); }); } useEffect(()=>{ RefreshEvents(); }, []); return ( <View> {!eventsHTML? <ActivityIndicator/> : <Text>Hello world</Text>} </View> ) } export default EventsScreen;
依赖配置(package.json)
{ "name": "bathe", "version": "1.0.0", "main": "node_modules/expo/AppEntry.js", "scripts": { "start": "expo start", "android": "expo start --android", "ios": "expo start --ios", "web": "expo start --web" }, "dependencies": { "@react-navigation/bottom-tabs": "^6.5.3", "@react-navigation/drawer": "^6.5.7", "@react-navigation/native": "^6.1.2", "@react-navigation/native-stack": "^6.9.8", "@reduxjs/toolkit": "^1.9.2", "cheerio": "^1.0.0-rc.12", "expo": "~47.0.12", "expo-status-bar": "~1.4.2", "firebase": "^9.16.0", "htmlparser2": "^8.0.1", "nativewind": "^2.0.11", "react": "18.1.0", "react-native": "0.70.5", "react-native-gesture-handler": "~2.8.0", "react-native-html-parser": "^0.1.0", "react-native-reanimated": "~2.12.0", "react-native-render-html": "^6.3.4", "react-native-safe-area-context": "4.4.1", "react-native-screens": "~3.18.0", "react-redux": "^8.0.5" }, "devDependencies": { "@babel/core": "^7.12.9" }, "private": true }
问题原因分析
- 状态类型不匹配:
eventsHTML初始值设为对象{},但后续存储的是字符串类型的HTML,类型不一致导致React DevTools对状态解析异常,出现循环引用的错误输出。 - 异步状态更新的时序问题:
setEventsHTML是异步操作,调用后立即执行ParseEventsHTML,此时读取的仍是旧状态值,而非刚更新的HTML内容。 - Expo Go初始加载的缓存/时序问题:首次启动时可能存在网络请求缓存或JS bundle加载时序异常,热重载后环境状态重置,请求恢复正常。
解决方案
1. 修正初始状态类型
将useState({})改为useState(''),确保状态类型与后续存储的HTML字符串一致。
2. 监听状态变化执行解析
通过useEffect监听eventsHTML的变化,确保只有状态更新完成且有内容时,才执行解析逻辑,避免读取旧值。
3. 添加请求错误处理
给Fetch请求添加错误捕获,避免请求失败时状态无更新,导致界面一直停留在加载状态。
修改后的代码
import React, { useEffect, useState } from 'react' import { ActivityIndicator, StyleSheet, Text, useWindowDimensions, View } from 'react-native'; const EventsScreen = () => { // 初始状态改为空字符串,匹配HTML内容类型 const [eventsHTML, setEventsHTML] = useState(''); const { width } = useWindowDimensions(); const ParseEventsHTML = () => { console.log(eventsHTML); // 这里可添加cheerio等HTML解析逻辑 }; const RefreshEvents = () => { console.log("refreshing events"); fetch('https://www.thesubath.com/whats-on/') .then(response => { // 检查响应状态是否正常 if (!response.ok) { throw new Error(`请求失败:${response.status}`); } return response.text(); }) .then(textResponse => { setEventsHTML(textResponse); }) .catch(error => { console.error('请求错误:', error); // 可在此添加错误提示逻辑 }); }; useEffect(() => { RefreshEvents(); }, []); // 监听状态变化,确保读取最新值 useEffect(() => { if (eventsHTML) { ParseEventsHTML(); } }, [eventsHTML]); return ( <View> {!eventsHTML ? <ActivityIndicator /> : <Text>已获取HTML内容</Text>} </View> ) }; export default EventsScreen;
额外排查建议
如果问题仍存在,可尝试:
- 在Expo Go设置中选择「Clear Cache」清除缓存;
- 重启Expo开发服务;
- 检查目标网站是否有反爬机制,可添加请求头模拟浏览器请求(比如
headers: {'User-Agent': 'Mozilla/5.0'})。
内容的提问来源于stack exchange,提问作者snakelovah18119
相关产品推荐
相关产品推荐

