0
function Painter({tempArr}) {
  const [arr, setArr] = useState([]);

  useEffect(() => {
    tempArr.map((item, index) => {
      setTimeout(() => {
        setArr([...arr, item]);
      }, 2000 * index)
    })
  }, [tempArr])

I checked the state arr has only one element in the array. I expected arr state will have all the elements of tempArr array after the last timeout. But there is only new element in every re-rendering.

I found using the updater function solves the issue.

function Painter({tempArr}) {
  const [arr, setArr] = useState([]);

  useEffect(() => {
    tempArr.map((item), index => {
      setTimeout(() => {
        setArr(prev => [...prev, item]); // using the updater function
      }, 2000 * index)
    })
  }, [tempArr])

But I don't know why this one works but not the above one.

nearworld
  • 25
  • 5
  • I assume this similar post will give you the explanation you need https://stackoverflow.com/questions/53024496/state-not-updating-when-using-react-state-hook-within-setinterval – Oshan Abeykoon Jan 21 '23 at 13:30

2 Answers2

0

You'll need to set incremental time in the timeout. You can multiply the constant time with the index to do so.

useEffect(() => {
  tempArr.map((item, index) => {
    setTimeout(() => {
      setArr([...arr, item]);
    }, 2000 * index)
  })
}, [tempArr])
Prayag Choraria
  • 710
  • 5
  • 15
  • My mistake.. I have that `2000 * index` part in my real code. But to accumulate elements in `arr` state, I need the updater function still. – nearworld Jan 21 '23 at 13:27
0

I don't know why this one works but not the above one.

setArr([...arr, item]);

The arr in this code is whatever arr was when the effect ran. So assuming this is the first render, arr is an empty array. You set several time outs, and every single one of them copies that empty array and adds in one item. They do not copy the most recent array, always the original array.

So the first timer to go off copies an empty array and adds the first item. Then the second timer copies the empty array and adds the second item. The first item is not in this array, because the second timeout doesn't know about that item. And so it continues, with each timeout overwriting the work that the previous one did, and only the last setState will persist.

setArr(prev => [...prev, item]);

When you switch to this version, you're now copying the most recent version of the array. So the first timeout copies the empty array and adds one item. Then the second array copies the array that has one item, and adds the second item. And so on, building up the array each time.

Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98