2

In my React app, I have an stateful array and setter [data, setData] which I would like to iterate through, and for each element, call a series of async functions.

I need each operation to occur sequentially, so my code looks like:

async save = () => {
  data.forEach(async(item) => {
    // Each of these are network requests, and they need to happen sequentially.
    await post();
    await update();
    await publish();
  });
};

My question is: What happens if, during this process, another process calls setData()? Is it possible that data will be mutated in the middle of save() being executed? If so, how will the forEach respond? Will it continue to iterate over the original state before the mutation, or will the mutation take effect within the context of the loop?

(I understand that I should avoid creating this type of situation in the first place, but if React has some sort of built in protection against this, then I'd like to avoid adding unnecessary abstraction to avoid something that won't actually happen)

Evan Lauer
  • 73
  • 8
  • 1
    Using async within forEach doesn’t usually work as one might think. See https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop – James Jul 21 '23 at 19:39
  • "*In my React app, I have an stateful array*" - you really should have an array that you are mutating. Surely the array is constant and never does change its contents or length. [Calling `setData` with a **new array**](https://react.dev/learn/updating-arrays-in-state) just causes another render with that separate array, not affecting the original `const` (and any iteration over it) at all. It's not exactly a built-in protection, but it's the standard that applies to any [well-built React app](https://react.dev/learn/thinking-in-react). – Bergi Jul 21 '23 at 19:43
  • @Bergi Hi, thanks for the response. I'm not sure exactly what you mean by "an array that you are mutating". In this case I need my component to re-render to reflect which of a series of items are selected. The total number of items is dynamic, so it seems to me that I need to store the selected items in an array. (I'm not too concerned about having to construct a new array each time because the number of items won't exceed ~15 elements). I suppose I could have the parent component pass in the items as child components, but this doesn't really make sense semantically in the context of my app. – Evan Lauer Jul 21 '23 at 19:52
  • @James Hi, thanks for the reading. I understand that the forEach loop will just fire off each of my functions, and it won't await them. This is okay for my app. Does this mean that the forEach is guaranteed to finish executing (as in, each function will be called and the loop exited) before any state change would occur? – Evan Lauer Jul 21 '23 at 19:53
  • @Bergi Saw your edit -- thank you, that makes sense. – Evan Lauer Jul 21 '23 at 19:55

0 Answers0