0

I have a main app render a GameCard component. I am storing an array of objects fetched in a useEffect to state with useState and setInterval to refetch every minute. I can log out the props passed in my GameCard component, but it will not render the mapped data. It will show the loading correctly and removes it once loaded, it will also show "Games" in a div. It shows what I have in state passed in props with React Devtools. I have no errors either. I feel like I almost have it or I've written this completely wrong.

I have check the docs but this might be a special case due to how I want to destructure the array in GameCard. I add the whole array of nested objects to state and destructure them in the return of GameCard.

Note: This api requires two separate fetches, one to get an array of links (not shown) and one to loop over each link to get each game's data.

App.js

import React, { useState, useEffect } from "react";
import "./App.css";
import getGameLinks from "./utils/getGameLinks";
import GameCard from "./GameCard";

function App() {
  const [games, setGames] = useState([]);
  const [link, setLink] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const getGameData = async () => {
      setLoading(true);
      if (link.length === 0) {
        const links = await getGameLinks(); // gets list of game links, required to get each game's data
        setLink(links);
      } else {
        const gameArray = [];
        link.forEach((link) => {
          fetch(link)
            .then((res) => res.json())
            .then((out) => gameArray.push(out));
        });
        const newGameArray = gameArray.sort((a, b) => a.gamePk > b.gamePk); // does not work
        setGames(newGameArray);
        setLoading(false);
      }
      const timer = setInterval(getGameData, 60000);
      return () => {
        clearInterval(timer);
      };
    };
    getGameData();
  }, [link]);

  return (
    <div className="App">
      <h1>Gameday</h1>
      <GameCard games={games} loading={loading} />
    </div>
  );
}

export default App;

GameCard.js

import React from "react";

const GameCard = ({ games, loading }) => {
  if (loading) return <p>Loading...</p>;
  if (!loading)
    return (
      <div>
        <p>Games</p>
        {games.map((games) => (
          <p key={games.gamePk}>
            {games.gameData.teams.home.name} vs {games.gameData.teams.away.name}
          </p>
        ))}
      </div>
    );
};

export default GameCard;
Jake
  • 3
  • 2
  • what exactly is the problem? you say it doesn't render, what doesn't render? can you render a div/the loading? – andrewgi Aug 16 '20 at 18:46
  • Yes it renders the Loading... and removes it when loaded. I updated my question thank you. – Jake Aug 16 '20 at 19:08
  • 1
    The line `link.forEach(link => ...)` is firing off a bunch of async calls but it is not going to wait for them to resolve before moving on to the sort method. You need to either `Promise.all` the entire `link` array to handle them as a batch or use a `for...of` loop to handle each request separately - see [this thread](https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop). – lawrence-witt Aug 16 '20 at 19:30
  • fetch is asynchronous. you are not waiting for the results and only updating the state with an empty array. Move the `setState` into the `then`. – andrewgi Aug 16 '20 at 19:34
  • @lawrence-witt so if I use a for...of to fetch I should remove my link state? Sorry I am pretty new. – Jake Aug 16 '20 at 21:14

1 Answers1

0

Regarding your comment, I haven't tested this but I believe your code will work if you replace the link.forEach(link => ...) method with:

const gameArray = [];

for (const l of link) {
  const response = await fetch(l);
  const out = await response.json();
  gameArray.push(out);
};

There shouldn't be a need to remove or change anything else. You may have to do some error handling in there as well of course.

lawrence-witt
  • 8,094
  • 3
  • 13
  • 32
  • Yeah that's what I had as well after I did some digging into your comment. Thanks so much. – Jake Aug 17 '20 at 00:21