Search code examples
javascriptfor-looppromisefetch

JS/React - How should I use a fetch call inside of a for loop?


I'm still a little unfamiliar with asynchronous functions beyond their simplest forms, so I'm hoping someone here can help me out.

Some information:

getCollection() returns an array of objects that look like this.

{
  "id": 1,
  "userId": 3,
  "gameId": 3498,
  "review": "Testing review for game 1"
},

getGameById() takes in a integer (the id of a game) and returns that game object from an external API.

gameArray should be getting filled with game objects whose IDs in the external API match the IDs from the array of objects provided by getCollection.

const [games, setGames] = useState([])

const getGames = () => {
        getCollection().then(userGames => {
            let gameArray = []
            for (const eachObj of userGames) {
                if (eachObj.userId === currentUserId) {
                    getGameById(eachObj.gameId).then(game => {
                        gameArray.push(game)
                        })
                }
            }
            Promise.all(gameArray).then(() => {
                console.log(gameArray) //logs empty array, but shouldn't be empty
                setGames(gameArray)
            })
        })
    }

I have never used Promise.all before, it's just something I saw as a possible solution to this issue I'm having.


Solution

  • Promise.all takes an array of promises.

    First you must build the array of promises. Then you must call Promise.all with this array to retrieve all the games :

    function getGames() {
        getCollection().then(userGames => {
            const gamePromises = userGames
                   .filter(userGame => userGame.userId == currenUserId)
                   .map(userGame => getGameById(userGame.gameId));
    
            Promise.all(gamePromises).then(games=> {
                console.log(games);
                setGames(games)
            });
        })
    }
    

    Here is another solution using async function which is maybe more readable

    async function getGames() {
      const userGames = await getCollection();
      const currentUserGames = userGames.filter(({userId}) => userId == currentUserId);
      const games = await Promise.all(userGames.map(({gameId}) => getGameById(gameId));
      setGames(games);
    }