Search code examples
reactjsuse-effectuse-state

State not update when using setter and setInterval in useEffect


I have the following code, which I expect it to print an extra 10 every 2 seconds on the screen. However, it only prints 10 once. console.log(digits) gave me the correct array of 10s. How can I add a 10 to the array every 2 seconds and print the updated array on the screen each time the 10 is added?

Code sandbox here: https://codesandbox.io/s/silly-https-zk58p?file=/src/App.js

import { useEffect, useState } from "react";
let data = [];
export default function App() {
  const [digits, setDigits] = useState([]);
  useEffect(() => {
    let timer = setInterval(() => {
      data.push(10);
      setDigits(data);
      console.log(digits);
    }, 2000);
    return () => clearInterval(timer);
  }, [digits]);

  return <div className="App">{digits}</div>;
}


Solution

  • The issue is with setDigits(data). With arrays, you should be executing setDigits([...data]).

    Another way would be doing this:

    let timer = setInterval(() => { 
        setDigits([...digits, 10]); 
    }, 2000);
    

    Whenever dealing with objects, you should treat them as immutables. What happened here is you modifying an array and puhsing the SAME array into a state. While the value might be different, the array is actually the same hence it does not update the render. Whenever doing [...data] it creates a new array with the same values hence trigger the update.

    useEffect picks up the new value change hence why it fires again(cant be observed by console.log()), but this does not trigger re-render of the component.