When clearInterval will be called - When the timer changes or When the render is unmounted with which the setInterval is associated

184 views Asked by At

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 answers

1
Vivek Doshi 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
Jonas Wilms 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