Assignments to the 'timeInterval' variable from inside React Hook useEffect will be lost after each render

Viewed 1976

I need the auto re-rendering every 6s and I defined the component like the following.

const KioskPage = () => {

  const [time, setTime] = useState(Date.now())

  useEffect(() => {

    timeInterval = setInterval(() => setTime(Date.now()), 60000)

    return () => {
      clearInterval(timeInterval)
    }
  }, [])
}

but I got the notification :

Assignments to the 'timeInterval' variable from inside React Hook useEffect will be lost after each render. To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property. Otherwise, you can move this variable directly inside useEffect react-hooks/exhaustive-deps

Why this happen? and How can I fix this issue?

Regards

1 Answers

Assignments to the 'timeInterval' variable from inside React Hook useEffect will be lost after each render.

To illustrate:

const KioskPage = () => {

  const [time, setTime] = useState(Date.now())

  let timeInterval;
  // ^^^^^ this piece of code gets run on each render, when state/prop changes.
  // this will, in practice, clear the `timeInterval` value set by your effect below, when the component re-renders after being mounted.

  useEffect(() => {

    timeInterval = setInterval(() => setTime(Date.now()), 60000)
    // ^^^^ this assignment gets run once when the component mounts

    return () => {
      clearInterval(timeInterval)
    }
  }, []);
  
  return (/* render something*/);
}

You can fix this by, as suggested, "move this variable directly inside useEffect".

const KioskPage = () => {
  const [time, setTime] = useState(Date.now())

  useEffect(() => {
    const timeInterval = setInterval(() => setTime(Date.now()), 6000);
    // ^^^^^^^^^^^^^^^

    return () => {
      console.log('clearing!');
      clearInterval(timeInterval)
    }
  }, []);

  const formatted = new Date(time).toLocaleTimeString();
  return (
    <h1>Time: {formatted}</h1>
  );
}
Related