Search code examples
javascriptreactjsreduxreact-reduxredux-thunk

Axios.get() inside a map function to get data for multiple objects returning promise object


I have been having a problem with an axios fetch call inside of a returned object from a Array.map function. Whenever I return the response it returns a promise object to the array with the data I need but I can't seem to parse the promise object to get the data I need from it. When I console.log the response I get a regular object and not a promise.

I have tried using Promise.all , using redux-thunk for dispatching (but this dispatches a different action for every array item), JSON.parse, JSON.stringify, however I can't seem to get the async to run in the array

export const checkStreamerStatus = streamers => {
  return{
    type: CHECK_STREAMER_STATUS,
    payload: {
      streamers: streamers.map(streamer => ({
        ...streamer,
        status: getStatus(streamer)
      }))
    }
  }
}

const getStatus = streamer => {
  return axios.get(`https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=${streamer.social.youtube}&type=video&eventType=live&key=[API KEY]`)
    .then(res => res.data)
    .catch(err => err)    
}

I expect the code to output an array of objects with the data from the fetch call as a new key in each object called "status", and then I expect to update my state in my reducer with the returned array.


Solution

  • As for approach

    but I can't seem to parse the promise object

    the main idea is: Promise is not about parsing data. It's about awaiting till data comes.

    It may be done with async/await(and using redux-thunk since we cannot just return action in synchronous way)

    export const checkStreamerStatus = (streamers) => async (dispatch) {
      dispatch({
        type: CHECK_STREAMER_STATUS,
        payload: {
          streamers: streamers.map(streamer => ({
            ...streamer,
            status: await getStatus(streamer)
          }))
        }
      });
    }
    

    The imperfection is all the getStatus will be called sequentially. And any next request will wait till previous is responded. To make all requests run in parallel we need to create N requests and then await for all with Promise.all:

    async function appendWithStatus(streamer) {
      return {
        ...streamer, 
        status: await getStatus(streamer);
      };
    }
    
    export const checkStreamerStatus = (streamers) => async (dispatch) => {
        const streamersWithStatus = await Promise.all(streamers.map(appendWithStatus));
        dispatch({
          type: CHECK_STREAMER_STATUS,
          payload: {
            streamers: streamersWithStatus,
          }
       });
    }