Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

218
Views
React API calls not fully completing before rendering

I'm essentially brand new to React, so please bear with me if there are any strange or obvious mistakes that I am missing.

I am looking to create a small little project with the National Hockey League statistics API and unfortunately have run into an issue pretty early on.

Essentially, what this code is trying to do right now is to fetch all of the current team ID's through https://statsapi.web.nhl.com/api/v1/teams, and then loop through each team's response and use it's unique ID to store every player ID currently playing in the league https://statsapi.web.nhl.com/api/v1/teams/ID/roster.

The API requests seem to be working just fine, however I'm running into an issue where the check for loading seems to be functioning improperly. If I say, for example

{loading ? <p>Loading...</p> : <p>{playerList[0].jerseyNumber}</p>}

I am given a "Cannot read properties of undefined" error message.

Is the way I attempted to signify loading incorrect? Is there a better way to be certain that the API requests are 100% finished before accessing the data?

Here is my code:

function App() {
    const [playerList, setPlayerList] = useState([]);
    const [loading, setLoading] = useState(true);

    useEffect (() => {
        fetch("https://statsapi.web.nhl.com/api/v1/teams")
            .then((teamsResponse) => teamsResponse.json())
            .then((teamsData) => {
                const teams = teamsData.teams;
                teams.forEach((team) => {
                    fetch("https://statsapi.web.nhl.com/api/v1/teams/" + team.id + "/roster")
                        .then((teamResponse) => teamResponse.json())
                        .then((teamData) => {
                            const roster = teamData.roster
                            roster.forEach((player) => {
                                setPlayerList((oldList) => [...oldList, player]);
                            });
                        });
                    });
                });

            setLoading(false);
    }, []);

    return (
        <div>
            {loading ? <p>Loading...</p> : playerList && <p>{playerList[0].jerseyNumber}</p>}
        </div>
    );
}
about 4 years ago · Juan Pablo Isaza
3 answers
Answer question

0

You're calling setLoading(false) outside of the fetch call. That is going to invoke the fetch and call setLoading(false) without waiting for the promise to resolve.

If you want the loading indicator to be set to false only after all of the roster fetch calls then you'll need to use Promise.all with a then. where you set the loading indicator to false, such as:

const teams = teamsData.teams;
const rosterRequests = teams.map(team => {
  fetch("https://statsapi.web.nhl.com/api/v1/teams/" + team.id + "/roster")
    .then(teamResponse => teamResponse.json())
    .then(teamData => {
      // Update roster state
    });

// This will be executed once all the team roster requests have completed
Promise.all(rosterRequests).then(() => setLoading(false));

You can read more about Promise.all here.

about 4 years ago · Juan Pablo Isaza Report

0

You are setting loading to false before the data is loaded. Try putting setLoading(false); into

                        .then((teamData) => {
                            const roster = teamData.roster
                            roster.forEach((player) => {
                                setPlayerList((oldList) => [...oldList, player]);
                            });
                            setLoading(false); <---
                        });
about 4 years ago · Juan Pablo Isaza Report

0

setLoading should be set to false when all promises are settled since there are nested requests, I have updated and tested the solution

Updated code

useEffect(() => {
    fetch("https://statsapi.web.nhl.com/api/v1/teams")
      .then((teamsResponse) => teamsResponse.json())
      .then((teamsData) => {
        const teams = teamsData.teams;
        let arr = [];

        const allRosterData = teams.map(async (team) => {
          const rosterData = await fetch(
            "https://statsapi.web.nhl.com/api/v1/teams/" + team.id + "/roster"
          )
            .then((teamResponse) => teamResponse.json())
            .then((teamData) => {
              const dt = [];
              const roster = teamData.roster;
              roster.forEach((player) => {
                dt.push(player);
              });

              return dt;
            });

          arr = [...arr, ...rosterData];

          return rosterData;
        });

        Promise.all(allRosterData)
          .then(() => {
            //Change state here when all promises are settled
            setPlayerList(arr);
            setLoading(false);
          })
          .catch((err) => {
            console.error(err);
          });
      });
  }, []);
about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!