Array map and asynchronous functions

Asked

Viewed 127 times

1

I’m using the function getStaticProps from Next.js and Axios to pick up news from Hacker News. My goal is to access the API that returns the main stories of the day (which returns a unique id of those stories) and then take the first five ids of that return and make a new request through Axios to access their content. At the end step the content as props for the component that will render the news.

The problem is that to get the first five I need to use map to access the results asynchronously. The console.log in the code returns empty precisely because of the time of the code. I already searched some results using Promise.all but none that applies to that case.

So the question is: How do I perform the process described above using map asynchronous?

export async function getStaticProps() {
  const res = await axios.get('https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty')
  const allData = await res.data
  
  let data = []

  allData.slice(0, 5).map(async function(story) {
    
    try {
      let itemRes = await axios.get(`https://hacker-news.firebaseio.com/v0/item/${story}.json?print=pretty`)
      const itemData = await itemRes.data
      
      data.push(itemData)
      
    } catch (e) {
      
      console.log(e)
      
    }
    
  })

  console.log(data)

  return {
    props: { data }
  }
}

1 answer

0


Are you using the map as a way to iterate over each element of the array. Let’s see its code:

allData.slice(0, 5).map(async function(story) {
  // ...
  let itemRes = await axios.get('...')
  const itemData = await itemRes.data
      
  data.push(itemData)
  // ...
})

Note that the callback that you went to map does not return any value. Therefore, the mapping is being done to undefined.

You must return the value you want. If you want to mount a new one array directly, use a for normal (but in this case it is not what you want).

Once you have an array of promises (created by mapping that explicitly returns promises or has callback being asynchronous function), you can use Promise.all. Behold:

export async function getStaticProps() {
  const res = await axios.get('...');
  const allData = res.data;

  const promises = allData.slice(0, 5).map(async function (story) {
    const itemRes = await axios.get('...');
    return itemRes.data;
  });

  try {
    const data = await Promise.all(promises);

    return {
      props: { data }
    };
  } catch (error) {
    console.error(error);

    return {
      props: { data: null }
    };
  }
}

Note that I made some modifications to the code: I added a semicolon and modified the place of the try-catch because of the functioning of Promise.all - learn more here.

Also note that the await in await res.data is not necessary, since data is not a promise.

For further study, read:

  • Thanks for the editing and comments. However, when you used Promise.all() I think you forgot to add files as a parameter. I added it to my code and it worked. If you can check this please.

  • That’s right, sorry for the error! It’s already edited. Thanks. :) cc @Mateusqueiros

Browser other questions tagged

You are not signed in. Login or sign up in order to post.