You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌套Fetch请求报错:Objects are not valid as a React Child问题排查

问题分析与修复方案

错误根源

  1. React组件不能是async函数:你将App声明为async function App(),但React组件必须返回JSX元素,async函数返回的是Promise,这直接触发了Objects are not valid as a React child (found: [object Promise])错误。
  2. 请求顺序未正确等待:第二个fetch没有等待第一个请求完成就执行,且用let声明的memberId会在组件重新渲染时重置,导致第二个请求拿到的是初始值0。
  3. useEffect无限触发:未给useEffect添加依赖数组,每次组件渲染都会重复发起请求。
  4. 渲染内容格式不合法: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 18:35:15