Home > front end >  updating a React array state in setTimeout callback function
updating a React array state in setTimeout callback function

Time:01-22

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.

CodePudding user response:

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])

CodePudding user response:

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.

  • Related