简体   繁体   中英

How to await data coming from an API as a prop in a component?

I am trying to send a prop on a component once my data loads from an API. However, even though I am using async await to await from my data, I am still getting an error of: 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. 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.

My process :

  • Have two set states: 1) updateLoading and 2) setRecordGames
  • Once the data is loaded, I will set updateLoading to false and then set recordGames with the data from the API.

My Problem : It seems that when I pass data in the component, React does not wait for my data load and gives me an error.

This is my code:


import useLoadRecords from '../../hooks/useLoadRecords'
import { CustomPieChart } from '../charts/CustomPieChart'

export const GameDistribution = () => {
const { records, loading } = useLoadRecords()
  let data = records

  console.log(data) // This logs out the records array

  return (
    <div>
      // once loading is false, render these components
      {!loading ? (
        <>
          <div>
            {recordGames.length > 0 ? (
              // This line seem to run as soon as the page loads and I think this is the issue. recordGames is empty at first, but will populate itself when the data loads
              records.length > 0 && <CustomPieChart data={data} />
            ) : (
              <div>
              No games
              </div>
            )}
          </div>
        </>
      ) : (
       <span>Loading...</span>
      )}
    </div>
  )
}

// useLoadRecords.js

import { useState, useEffect } from 'react'
import { API } from 'aws-amplify'
import { listRecordGames } from '../graphql/queries'

// Centralizes modal control
const useLoadRecords = () => {
  const [loading, setLoading] = useState(false)
  const [records, updateRecords] = useState([])

  useEffect(() => {
    fetchGames()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  const fetchGames = async () => {
    try {
      let recordData = await API.graphql({
        query: listRecordGames,
      })

      setLoading(false)

      let records = recordData.data.listRecordGames.items.map(
        (item) => item.name
      )
      let result = Object.values(
        records.reduce((acc, el) => {
          if (!acc[el]) acc[el] = { name: el, plays: 0 }
          acc[el].plays++
          return acc
        }, {})
      )
      updateRecords(result)
    } catch (err) {
      console.error(err)
    }
  }

  return { records, loading }
}

export default useLoadRecords

I would make a hook for the data and setData to it when fetching, you can clone the data using spread operator and this pass it. or better return that component only if there is something in data for example

{
data &&  <CustomPieChart data={recordGames} />
}

and it would be nice to make a some loader (gif/svg) using your loading hook so it can be shown when the data is still being fetched.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM