Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

95
Views
setState loop seems to only run on the last iteration

So I have an app with friends and events, where each friends has specific events.
I just want to retrieve every single event from every single friend.
I have an 'event' state const [events, setEvents] = useState([]);
Then here is the problematic useEffect snippet:

useEffect(() => {
  getFriendsIds()
    .then(idsArray => {
      Promise.all(idsArray.map(id => {
        getUserEvents(id)
          .then(evs => {
            if (evs.length > 0) {
              for (let i=0; i<evs.length; i++) {
                setEvents([...events, evs[i]]);
              }
            }
          })
      }))
    })
}, [])

This should store the aforementioned events in the 'events' state variable.
However, when I try to render them with {events.map(ev => renderItem(ev))}, I only get the very last event of the last friend in the loop (It is guaranteed that renderItem works fine).
I would love an explanation of how this works, and if possible an alternative algorithm that actually achieves what I aim to do.
Thanks

about 4 years ago · Juan Pablo Isaza
3 answers
Answer question

0

Actually, this happens because your useEffect() doesn't have the events state in its dependency array.

useEffect(() => {
   ...
}, [events])

However event this solution will not work properly because the setState() function works asynchronously.

You have to use state updater function in this case:

useEffect(() => {
  ...
  setEvents((prevEvents) => [...prevEvents, evs[i]]);
  ...
}, []);

Read more about dependency array and state updater in the official documentation

about 4 years ago · Juan Pablo Isaza Report

0

Try passing a function to setEvents and remove the for loop.

if (evs.length > 0) {
    setEvents((prev) => ([...prev, ...evs]));
}
about 4 years ago · Juan Pablo Isaza Report

0

Move the setState out of the loop -

useEffect(async () => {
  const ids = await getFriendsIds()
  const events = await Promise.all(ids.map(getUserEvents)))
  setEvents(events.flat())      // replace
}, [])

If you want to append events to the existing events state, you can use a functional update -

useEffect(async () => {
  const ids = await getFriendsIds()
  const events = await Promise.all(ids.map(getUserEvents)))
  setEvents(r => [...r, ...events.flat()])    // append
}, [])

You can use .flat instead of checking for .length as it will remove empty arrays for you automatically -

const a = [["event1", "event2"], [], ["event3"], ["event4"], []]

console.log(a.flat())
// ["event1", "event2", "event3", "event4" ]

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!