Home > Net >  Fetch Inside A Fetch - Objects Are Not Valid As A React Child
Fetch Inside A Fetch - Objects Are Not Valid As A React Child

Time:11-25

I am trying to make two fetch requests. The second one cannot be completed until MemberId is retrieved from the first one. I have tried putting them in separate async functions but keep getting the below error.

Any insights on the best way to do this would be much appreciated.

Error message: Uncaught Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.

import { StatusBar } from "expo-status-bar";
import { useEffect, useState } from "react";
import { StyleSheet, Image, Text, View } from "react-native";

export default async function App() {
  const [isLoading, setLoading] = useState(true);
  const [isLoadingMp, setLoadingMp] = useState(true);
  const [data, setData] = useState([]);
  const [mpData, setMpData] = useState([]);
  let memberId = 0;

  useEffect(() => {
    fetch(
      `https://members-api.parliament.uk/api/Members/Search?Name=Boris Johnson`
    )
      .then((response) => response.json())
      .then((json) => {
        setMpData(json);
        memberId = json.items[0].value.id;
        console.log("memberId:", memberId);
      })
      .catch((error) => console.error(error))
      .then(
        fetch(
          `https://commonsvotes-api.parliament.uk/data/divisions.json/membervoting?memberId=${memberId}`
        )
          .then((response) => response.json())
          .then((json) => setData(json))
          .catch((error) => console.error(error))
          .finally(() => setLoading(false))
          .finally(() => {
            setLoadingMp(false);
          })
      );
  });

  return (
    <View style={{ flex: 1, padding: 24 }}>
      {isLoading || isLoadingMp ? (
        <Text>Loading...</Text>
      ) : (
        <View style={styles.container}>
          <Text>
            <Image
              source={{
                uri: `${mpData.items[0].value.thumbnailUrl}`,
                width: 60,
                height: 60,
              }}
            />
            <Text>{`${mpData.items[0].value.id}\n`}</Text>

            {data.map((individualData) => {
              return `\nDate: ${
                individualData.PublishedDivision.Date
              }\nDivision id: ${
                individualData.PublishedDivision.Date
              }\nDivision title: ${
                individualData.PublishedDivision.Title
              }\nVoted: ${!!individualData.MemberVotedAye ? "Yes" : "No"}\n`;
            })}
          </Text>
          <StatusBar style="auto" />
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});

CodePudding user response:

import { StatusBar } from "expo-status-bar";
import { useEffect, useState } from "react";
import { StyleSheet, Image, Text, View } from "react-native";

export default function App() {
  const [isLoading, setLoading] = useState(true);
  const [isLoadingMp, setLoadingMp] = useState(true);
  const [data, setData] = useState([]);
  const [mpData, setMpData] = useState([]);
  let memberId = 0;

  useEffect(() => {
    const callApi = async ()=>{//defining a async function to call the API
      
      setLoading(true);//maybe you just need one loading flag
      try{

      const result = await (await fetch(
      `https://members-api.parliament.uk/api/Members/Search?Name=Boris Johnson`
      )).json();//first api and json() its result
      const memberId = result.items[0].value.id;//get the member id from it
      
      const finalResult = await(await fetch(
          `https://commonsvotes-api.parliament.uk/data/divisions.json/membervoting?memberId=${memberId}`
        )).json();//second api call and json() its result
        //set the state
        setData(finalResult);
        setMpData(result);
      }catch(e){
        console.log(e)
      }finally{
          setLoading(false);//set loading false in both the fail and success case
      }
    }
    callApi();//calling the function
  }, []);

 //VIEW rendering
  return (<View style={{ flex: 1, padding: 24 }}>
      {isLoading ? (
        <Text>Loading...</Text>
      ) : (
        <View style={styles.container}>
          <Text>
            <Image
              source={{
                uri: `${mpData.items[0].value.thumbnailUrl}`,
                width: 60,
                height: 60,
              }}
            />
            <Text>{`${mpData.items[0].value.id}\n`}</Text>

            {data.map((individualData) => {
              return `\nDate: ${
                individualData.PublishedDivision.Date
              }\nDivision id: ${
                individualData.PublishedDivision.Date
              }\nDivision title: ${
                individualData.PublishedDivision.Title
              }\nVoted:  ? "Yes" : "No"}\n`;
            })}
          </Text>
          <StatusBar style="auto" />
        </View>
      )}
    </View>);
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});

CodePudding user response:

This specific problem has nothing to do with the fetches, it is simpler.

You declared your functional component as async:

export default async function App() {

The consequence is that it doesn't return a React element but a Promise that resolves to a React element, which React can't handle.

Remove the async:

export default function App() {
  • Related