嵌套Fetch请求报错:Objects are not valid as a React Child问题排查
问题分析与修复方案
错误根源
- React组件不能是async函数:你将
App声明为async function App(),但React组件必须返回JSX元素,async函数返回的是Promise,这直接触发了Objects are not valid as a React child (found: [object Promise])错误。 - 请求顺序未正确等待:第二个
fetch没有等待第一个请求完成就执行,且用let声明的memberId会在组件重新渲染时重置,导致第二个请求拿到的是初始值0。 - useEffect无限触发:未给
useEffect添加依赖数组,每次组件渲染都会重复发起请求。 - 渲染内容格式不合法:
data.map返回的是字符串数组,不符合React子元素的规范要求。
修复后的完整代码
import { StatusBar } from "expo-status-bar"; import { useEffect, useState } from "react"; import { StyleSheet, Image, Text, View } from "react-native"; // 移除async,组件必须是普通函数 export default function App() { const [isLoading, setLoading] = useState(true); const [data, setData] = useState([]); const [mpData, setMpData] = useState(null); // 初始设为null,避免渲染时报错 const [memberId, setMemberId] = useState(null); // 用状态存储memberId useEffect(() => { // 用async函数处理顺序请求 const fetchData = async () => { try { // 第一个请求:获取议员信息 const mpResponse = await fetch( `https://members-api.parliament.uk/api/Members/Search?Name=Boris%20Johnson` ); const mpJson = await mpResponse.json(); setMpData(mpJson); // 提取memberId并更新状态 const id = mpJson.items[0].value.id; setMemberId(id); // 第二个请求:依赖memberId获取投票信息 const voteResponse = await fetch( `https://commonsvotes-api.parliament.uk/data/divisions.json/membervoting?memberId=${id}` ); const voteJson = await voteResponse.json(); setData(voteJson); } catch (error) { console.error("请求出错:", error); } finally { // 请求完成后关闭加载状态 setLoading(false); } }; fetchData(); }, []); // 空依赖数组,确保只在组件挂载时执行一次 if (isLoading || !mpData || !memberId) { return ( <View style={{ flex: 1, padding: 24, alignItems: 'center', justifyContent: 'center' }}> <Text>Loading...</Text> </View> ); } return ( <View style={{ flex: 1, padding: 24 }}> <View style={styles.container}> <View style={{ alignItems: 'center', marginBottom: 20 }}> <Image source={{ uri: mpData.items[0].value.thumbnailUrl, width: 60, height: 60, }} style={{ borderRadius: 30 }} // 可选:给头像加圆角 /> <Text style={{ marginTop: 8 }}>ID: {mpData.items[0].value.id}</Text> </View> <View style={{ width: '100%' }}> {data.map((item, index) => ( <Text key={index} style={{ marginBottom: 12, padding: 8, backgroundColor: '#f5f5f5', borderRadius: 4 }}> Date: {item.PublishedDivision.Date}\n Division ID: {item.PublishedDivision.DivisionId}\n Division Title: {item.PublishedDivision.Title}\n Voted: {item.MemberVotedAye ? "Yes" : "No"} </Text> ))} </View> <StatusBar style="auto" /> </View> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "flex-start", // 改为flex-start,避免内容居中挤压 paddingTop: 20, }, });
关键修改说明
- 移除组件async声明:确保组件返回合法的JSX元素,解决核心错误。
- 用状态存储memberId:避免let变量在渲染时重置,确保第二个请求能拿到正确的ID。
- async/await处理顺序请求:清晰控制请求顺序,确保第二个请求在第一个完成后执行。
- 添加useEffect依赖数组:空数组确保请求只执行一次,避免无限循环。
- 优化渲染逻辑:
- 增加加载状态的判断,确保
mpData和memberId存在后再渲染内容,避免报错。 - 用
Text组件包裹每个投票条目,符合React子元素规范,同时添加样式提升可读性。 - 调整布局样式,让内容展示更合理。
- 增加加载状态的判断,确保
内容的提问来源于stack exchange,提问作者Tardigrade77
相关产品推荐
相关产品推荐

