I'm a beginner in React and stuck with some problem. When the setInterval associated with a particular renders gets cleared?



import React, { useState, useEffect, useRef } from "react";
import ReactDOM from "react-dom";

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    let id = setInterval(() => {
      setCount(count + 1);
    }, 1000);
    return () => clearInterval(id);
  },[]);

  return <h1>{count}</h1>;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Counter />, rootElement);
2

There are 2 best solutions below

1
On BEST ANSWER

It will get cleared on component unmount event :

useEffect(() => {
    let id = setInterval(() => {
      setCount(count + 1);
    }, 1000);
    return () => clearInterval(id); // <-- get called on component unmount
  },[]); // <--- get called once component mounted/rendered first time

For more details : DO READ

When exactly does React clean up an effect?

React performs the cleanup when the component unmounts. However, as we learned earlier, effects run for every render and not just once. This is why React also cleans up effects from the previous render before running the effects next time.

0
On

I think your actual problem is that the timer only updates once, right? Well thats because you lied to React about your dependencies, your effect uses count, add that as an dependency:

 useEffect(() => {
   let id = setInterval(() => {
     setCount(count + 1); // here you use count
   }, 1000);
   return () => clearInterval(id);
 }, [count]); // here you have to tell react about your dependencies

Now the function returned from the effect will be called whenever count changes, or when the component unmounts. So you could actually write your code as:

 useEffect(() => {
   let id = setTimeout(() => {
     setCount(count + 1);
   }, 1000);
   return () => clearTimeout(id);
 }, [count]);

This basically does: Whenever 'count' changes, shedule a timer to change 'count' again in 1 second.

However, using an interval that runs as long as the component is mounted would work too, but for that to work we need to (1) remove all dependencies (count) and (2) get the latest count somehow. Fortunately the state setter also takes a callback:

 useEffect(() => {
   let id = setInterval(() => setCount(count => count + 1), 1000);
   return () => clearInterval(id);
 }, []); // we don't lie anymore