Nick Kinlen
Nick Kinlen

Reputation: 1406

React useEffect and Axios: Making chained API calls within 'then'

I'm working with the NHL API and retrieving hockey stats for my app. The API has multiple endpoints that I'm using to access player stats.

Roster endpoint

https://statsapi.web.nhl.com/api/v1/teams/3/roster

After I retrieve this data I can access an object called person which contains an ID number for that individual player's API endpoint that contains pedigree information (i.e. country they are from, height/weight, etc..). I can then send an API request that looks like this to retrieve more data for that individual player, in this case 8476191 is the ID number.

Pedigree Info endpoint:

https://statsapi.web.nhl.com/api/v1/people/8476191

I can also pass the ID number, 8476191, to a stats endpoint which contains stats for the same player.

Stats endpoint:

https://statsapi.web.nhl.com/api/v1/people/8476191/stats?stats=statsSingleSeason&season=20182019

What I would like to do is send a request to the Roster endpoint, grab the ID numbers for every player on the roster, and then make subsequent API calls to the Pedigree info endpoint and the stats endpoint using the ID number.

How can I make an Axios get request to the roster endpoint and then nest two more get requests within the call that can access the ID number from the first call? Here is what I attempted:

// State for retrieving player ID numbers from roster endpoint
const [playerIDNumbers, setPlayerIDNumbers] = useState([]);

useEffect(() => {
    // Get the roster data, set playerIdNumbers to an array containing all the ID numbers
   axios.get(`https://statsapi.web.nhl.com/api/v1/teams/${teams[teamName].id}/roster`)
       .then(res => {
           setPlayerIDNumbers(Object.values(res.data.roster).map((x) => {
               return x.person.id;
           }));
           // res now contains all the ID numbers
           console.log(res);
       })
       // After grabbing all the ID numbers for each player on the roster, I want to map through each ID 
       // in the array and send a request for each player's pedigree data
       .then(res => {
           // Later in my code I created an array to contain the IDs called playerIDArr
           playerIDArr.map((playerID) => {
               axios.get(`https://statsapi.web.nhl.com/api/v1/people/${playerID}/`)
           })
           console.log('Player ID call returned : ' + res);
       })
       // After this is done I want to make a third request using the ID numbers to grab the stats /////from the stats endpoint
       /* Stats Axios request would go here */
       .catch(err => {
           console.log('Error : ' + err);
       })
}, [])

Upvotes: 2

Views: 4806

Answers (1)

thedude
thedude

Reputation: 9814

No need to keep the state, here is how to do this using a closure:

useEffect(() => {
  axios.get(`https://statsapi.web.nhl.com/api/v1/teams/${teams[teamName].id}/roster`)
    // get all ids
    .then(res => Object.values(res.data.roster).map((x) => x.person.id))
    // map through ids and retrieve the data 
    .then(ids => {
      const people = Promise.all(ids.map(id => axios.get(`https://statsapi.web.nhl.com/api/v1/people/${id}/`)))

      const stats = Promise.all(ids.map(id => axios.get(`https://statsapi.web.nhl.com/api/v1/stats/${id}/`)))

      return Promise.all([people, stats])

    }).catch(err => {
      console.log('Error : ' + err);
    })
})

// or using async/await, and some refactoring

const getRoster = id => axios.get(`https://statsapi.web.nhl.com/api/v1/teams/${id}/roster`)

const getPerson = id => axios.get(`https://statsapi.web.nhl.com/api/v1/people/${id}/`)

const getStats = id => axios.get(`https://statsapi.web.nhl.com/api/v1/stats/${id}/`)

useEffect(() => {
  const res = await getRoster(teams[teamName].id)
  const ids = Object.values(res.data.roster).map(x => x.person.id)
  return Promise.all(ids.map(id => Promise.all([getPerson(id), getStats(id)])))
})

Upvotes: 2

Related Questions