React Native应用为何反复发起网络请求?
React Native页面反复发起数百次请求问题解决
问题描述
目前仅在Android端测试,从服务器获取JSON数据以卡片形式展示,数据能正常显示,但应用会反复向服务器发起数百次请求。该页面通过导航栈与其他页面关联,登录页请求正常,仅此页面存在问题。
问题页面代码:
function WorkOrders({ navigation }) { const [data, setData] = useState("") fetch(`https://www.example.com/workorder?user=${global.email}`, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } }) .then((response) => response.json()) .then((response) => { setData(response) }) if(!!data["id"]){ return ( <ScrollView> <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Work Orders assigned to me</Text> <Card> <Card.Title>Work Order #{data["id"]}</Card.Title> <Card.Divider/> <Text>Creation date: {data["creationDate"]}</Text> <Text>Due Date: {data["dueDate"]}</Text> <Card.Divider/> <Text>Work Location: {data["workLocation"]}</Text> <Card.Divider/> <Text>Description: {data["workDetails"]}</Text> </Card> </View> </ScrollView> ); } else { return( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>You don't have any assigned work orders.</Text> </View> ); } }
问题分析
核心问题是**fetch请求直接放在组件顶层代码中**:React组件每次渲染(初始渲染、state更新后、父组件触发重渲染等)都会执行顶层代码。当setData(response)更新state时,组件会重新渲染,再次执行fetch,再次更新state,形成无限循环,导致大量重复请求。
另外,data初始化为空字符串"",后续转为对象,判断data["id"]时存在类型逻辑隐患。
修复方案
1. 使用useEffect包裹请求逻辑
useEffect可以控制副作用(如网络请求)的执行时机,避免每次渲染重复执行。空依赖数组[]确保请求仅在组件挂载时执行一次。
2. 初始化合理的state类型
将data初始化为空对象{},匹配后续返回的JSON数据类型,避免类型判断错误。
3. 添加错误处理
网络请求可能失败,通过try/catch捕获错误,避免应用崩溃。
修复后的代码:
import { useEffect, useState } from 'react'; import { ScrollView, View, Text } from 'react-native'; // 确保Card组件已正确导入 function WorkOrders({ navigation }) { // 初始化data为空对象,匹配后续数据类型 const [data, setData] = useState({}); useEffect(() => { const fetchWorkOrders = async () => { try { const response = await fetch(`https://www.example.com/workorder?user=${global.email}`, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } }); const responseData = await response.json(); setData(responseData); } catch (error) { console.error('工单数据请求失败:', error); // 可在此添加用户可见的错误提示,比如设置error state } }; fetchWorkOrders(); }, []); // 空依赖数组:仅组件挂载时执行一次 // 简化id判断逻辑 if (data.id) { return ( <ScrollView> <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Work Orders assigned to me</Text> <Card> <Card.Title>Work Order #{data.id}</Card.Title> <Card.Divider /> <Text>Creation date: {data.creationDate}</Text> <Text>Due Date: {data.dueDate}</Text> <Card.Divider /> <Text>Work Location: {data.workLocation}</Text> <Card.Divider /> <Text>Description: {data.workDetails}</Text> </Card> </View> </ScrollView> ); } else { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>You don't have any assigned work orders.</Text> </View> ); } }
额外提示
- 如果需要根据变量(如用户切换)重新请求,可将变量加入
useEffect的依赖数组,例如[global.email],但需确保变量引用稳定(可变值可结合useRef处理)。 async/await相比链式then更易读,推荐用于异步逻辑编写。
内容的提问来源于stack exchange,提问作者Carlos Morin
相关产品推荐
相关产品推荐

