1

I am having some trouble finding a way to get this to work. Basically I get a list of users from a mock api endpoint and what I want to do is actually map each user to only have an email.

// returns 10 users from mock api so we have something to work with
function getUsers() {
  return fetch('https://jsonplaceholder.typicode.com/users')
    .then(res => res.json())
    .then(data => {
      console.log(data)
      return data
    })
}

// this just gives us something to map over
const usersList = getUsers()


// get specific user by id e.g. /users/1
const mappedUsers = (users) => {
    return users.map(async user => {
      // get a specific user by id
      const response = await fetch(`https://jsonplaceholder.typicode.com/users/${user.id}`)
      const userData = await response.json()

      // and only return the email property from the api reponse for each user
      return {
        userEmail: userData.email
      }
    })
}

mappedUsers(usersList)

The end result should just look like this:

mappedUsers = [
  { userEmail: 'name of the first email from api' },
  { userEmail: '...' },
  ...
]
dbzx10299
  • 722
  • 2
  • 14
  • 2
    Thanks for including enough code for us to clearly see the problem, you'd be surprised how often people don't do that. :-) `userList` will be a *promise*, not an array. You have to hook into the settlement of the promise and then use the fulfillment value. Similarly, `mappedUsers` will be an array of promises, so you have to wait for the promises to settle (usually by using `Promise.all`) and then access their fulfillment values. See the answers to the linked questions for details. – T.J. Crowder Nov 02 '22 at 12:11
  • 1
    Side note: Your code is falling prey to the footgun in the `fetch` API I describe [here](http://blog.niftysnippets.org/2018/06/common-fetch-errors.html) (my anemic old blog). `fetch` only rejects its promise on *network* errors, not HTTP errors. You have to check for HTTP errors on purpose (by checking `ok` on the response before reading the response body). – T.J. Crowder Nov 02 '22 at 12:12
  • Got it thanks, I will check into this deeper. I had a feeling something was bad using await each time because each iteration would be pausing essentially. – dbzx10299 Nov 02 '22 at 12:16
  • 1
    Nope, that's fine. :-) `map` does its work synchronously. When you call an `async` function, it's synchronous up until the first `await`, `return`, or `throw`; at that point, the function returns a promise. So `map` synchronously starts each `fetch` and builds an array of the promises, allowing the network operations to run in parallel. – T.J. Crowder Nov 02 '22 at 12:20
  • I read your links here and I‘m still a but confused how to achieve my end result. I want to return a new user object for each item in the array that is mapped. But each iteration needs to wait for the fetch request. So where would be the right place to create a promises array and how would the list of promises know what object they belong to? Async functions return a promise and basically the object propety in the map function is a promise that needs to have `.then` called on it to access the property – dbzx10299 Nov 02 '22 at 12:57
  • 1
    It would look something like this (though there are several ways to do it): https://jsfiddle.net/tjcrowder/2zdpxmha/1/ – T.J. Crowder Nov 02 '22 at 13:05
  • Thanks! I get it now that got it to click – dbzx10299 Nov 02 '22 at 13:15

0 Answers0