Next.js Discord

Discord Forum

Fetching data in [].map

Answered
Polish posted this in #help-forum
Open in Discord
PolishOP
[].map(async(opt, i) => {}) is throwing the Error: async/await is not yet supported in Client Components. I thought this was exclusive to the root element.

1. Is this a bug?
2. If it isn't a bug how would you recommend fetching data that is needed inside the [].map
Answered by luis_llanes
You can’t return a Promise inside the JSX, you’re mapping each array item to a Promise and React is expecting a React element
View full answer

46 Replies

Can you show us the code where you’re trying to do that?

The error says “async/await” isn’t valid syntax in client components which is completely true and not a bug
@luis_llanes Can you show us the code where you’re trying to do that? The error says “async/await” isn’t valid syntax in client components which is completely true and not a bug
PolishOP
I am confused.

export default function FunctionName() {
  // this async works
  async function getData() {
      // logic
  }

  return (<Box>
  // this async doesn't work
  {array.map(async(opt, i) => {}
    // logic
  )}
  </Box>)
}
You can’t return a Promise inside the JSX, you’re mapping each array item to a Promise and React is expecting a React element
Answer
I need to get data based on the array values
If you’re fully on the client what you can do is moving the nested fetching logic up to an effect and store in State all the data along with the mapped results from the nested fetch, all resolved so they are no longer a promise.
Then in JSX map over the state with the full data instead of partial data + promises.

If there’s a way you can get the Client component to receive the array of data by props, you do that better.
Like a parent component that’s a Server Component does the mapping, awaits the promises and gets the values, then just pass the array with the values. ?

Hard to know the whole context based on that code snippet alone
PolishOP
export default function FunctionName() {
  let [array, setArray] = useState(null);

  async function getData() {
    // logic
    setArray(data)
  }
  useEffect(() => {
    if (profile.pds) {
      getData();
    }
  }, []);

  return (<Box>
  {array.map(async(opt, i) => {
    // other logic
    let embed;
    if (opt.embed.type === "something") {
      let data = await fetch(opt.embed.url)
      // logic
      embed = <Component>{data.something}</Component>
    }
    return (<Box>
      // other relevant components
      {embed}
    </Box>)
  })}
  </Box>)
}
I had a lot of other logic in the map that works fine and doesn't need to await since it is just reading the values. It is only until I noticed opt.embed has a url that needs to be fetched for additional data that I encountered my problem
Is there a way you can move all the fetching logic out of your component?

Like moving getData() to the parent Server Component and once you fetch the data and the do the nested fetch call, etc, only then pass the data down to your component?
This page will eventually include interaction code. Once a user clicks load more it will fetch more data from getData or a similar function.
Looks over complicated
@luis_llanes Looks over complicated
PolishOP
In what sense? API 1 has the profile data that is needed to hydrate the page. API 2 fetches additional data to hydrate the posts.
The structure you shared omitting all the actual code looks messy because I don’t know the whole context. And I don’t know what profile.pds means and why getData only runs when that is truthy
PolishOP
I actually thought of one solution. When I execute API 1, I will immediately loop through the data, make API 2 requests, and append the API 2 data to API 1 data.
@Polish I actually thought of one solution. When I execute API 1, I will immediately loop through the data, make API 2 requests, and append the API 2 data to API 1 data.
PolishOP
@luis_llanes Pretty sure this will work in theory for my purpose. Unless you can think of another solution.
I thought about that solution up when I asked if it needed to be all client side (idk why but ok) i thought you weren’t considering it
Oh that’d be the best approach but you said you needed it to be all client side for specific reasons
@luis_llanes I thought about that solution up when I asked if it needed to be all client side (idk why but ok) i thought you weren’t considering it
PolishOP
Nope. It just didn't cross my mind. Until just now. Thinking about a solution lol
Yes that will work clientside but if the fetch calls take time you’ll have an empty page until all data resolved including the nested api calls
You’ll have to handle a loading state lol
@luis_llanes You’ll have to handle a loading state lol
PolishOP
Oh that was the first thing implemented. User experience is important lol
Good to know, I couldn’t see that in the code you sent 😹 anyway
@luis_llanes Good to know, I couldn’t see that in the code you sent 😹 anyway
PolishOP
Oh yeah, the loading state was technically not relevant lol. But thanks for helping me think through this. Sometimes just typing it out and discussing it with someone makes you realize you aren't considering the obvious options lol
You’re not using React Query or SWR right?
@luis_llanes You’re not using React Query or SWR right?
PolishOP
I am not. Just fetch. Why? 👀
Just asking, It would’ve helped a lot with the data fetching and loading states, error handling, etc, and eventually the click to load more infinite queries.

React Query != fetch tho, you still need to use fetch (or any async function, basically anything that returns a promise) it only handles the asynchronous state for you
The fetches will be the fetches anywhere you implement them, what’s different is handling everything that comes with an async function.

For example you will handle SWR or React Query your getData() function but instead of setting the state yourself inside of the function it will have to return the data, and the library will handle all the rest for you. Idk if it makes sense

Also I would recommend React Query since that’s the one I’ve used
If your app will handle a lot of Client side fetching React Query can make your life way easier.
PolishOP
@joulev Why was my marked solution changed? I marked the correct solution....
I believe he marked the answer to the actual question, the solution was a result of knowing why it was failing in the first place
Yes. The answer is not necessarily what ends up working for the OP. The answer is the answer to the original question asked in the post.
@joulev Yes. The answer is not necessarily what ends up working for the OP. The answer is the answer to the original question asked in the post.
PolishOP
My question was to find a solution to fetch the data. The message I marked was that solution.
I'm not sure why it would be changed when I'm the one who asked the question and should decide what the solution is for me.
@Polish My question was to find a solution to fetch the data. The message I marked was that solution.
Fair enough, you can always change the selected answer.

It’s just useless internet points at the end of the day. I wanted to get people who read the question on search engines to learn the answer to that question, they need not know nor care what ends up working in the OP’s specific circumstances
@joulev Fair enough, you can always change the selected answer. It’s just useless internet points at the end of the day. I wanted to get people who read the question on search engines to learn the answer to that question, they need not know nor care what ends up working in the OP’s specific circumstances
PolishOP
Hmm, I didn't know it was points but it explains why it was changed. Well it doesn't matter. I just noticed the change and was curious as to why since it felt weird. However I recommend as a moderation team you should have a really compelling reason to change the marked solution that the OP set. Since the post is specifically for the OP the answer should be specific for them.