Help understanding Pomodoro Clock setInterval

In working on the Pomodoro clock challenge I have achieved my first goal, which is just to count down using setInterval. This setInterval call was improperly executing at an exponential rate over time

import React, { useState, useEffect, useRef } from "react";
import "./App.css";

function App() {
  const [seconds, setSeconds] = useState(59);

useEffect(() => {
    var myVar = setInterval(myTimer, 1000);
  
  });

 function myTimer() {
    setSeconds(seconds - 1);}

 return (
    <div className="App">
      <div id="date">{dateTest}</div>
      <div id="clock">{seconds}</div>
    </div>
  );
}

export default App;


I found out that I had to add clearInterval and now it works:

import React, { useState, useEffect, useRef } from "react";
import "./App.css";

function App() {
  const [seconds, setSeconds] = useState(59);

useEffect(() => {
    var myVar = setInterval(myTimer, 1000);
    return () => clearInterval(myVar);
  });


  function myTimer() {
    setSeconds(seconds - 1);}

 return (
    <div className="App">
      <div id="clock">{seconds}</div>
    </div>
  );
}

export default App;

My question: Regarding these instructions “Above all, when using setInterval, it is imperative that you clear the scheduled interval once the component unmounts”, does this mean that every time myTimer() is called in setInterval, it mounts AND THEN UNMOUNTS?

I don’t understand why I needed to add:
return () => clearInterval(myVar);

Thanks for your continued help,

Gabriel H.

It’s other way around: it first unmounts and then mounts.
From docs (https://reactjs.org/docs/hooks-effect.html):

Does useEffect run after every render? Yes! By default, it runs both after the first render and after every update. (We will later talk about how to customize this.) Instead of thinking in terms of “mounting” and “updating”, you might find it easier to think that effects happen “after render”. React guarantees the DOM has been updated by the time it runs the effects.

So effectively you could replace setInterval with setTimeout and your code will still work.

So the DOM renders, then useEffect calls myTimer(), yes?

And is myTimer already rendered(this means mounted?) before useEffect calls it? It seems to me that only the elements in the return (the divs) are mounted upon first render, before useEffect calls anything.

Thanks for your help. Sorry if I am a bit slow. A little more explanation of the life-cycle would really help me understand React. I’m struggling on every assignment because I don’t understand the life-cycle well.

Yes. DOM renders, and useEffect gets called, which calls setInterval. After 1 second (more or less) myTimer gets called, which updates seconds, which triggers useEffect. It sees that it has return function, so this return function gets called first to do cleanup and then the cycle continues (setInterval -> myTimer -> setSeconds -> useEffect…)

myTimer is a function, it doesn’t get mounted nor rendered. But after initial render it exists and is ready to be called.

If you want a really deep dive into useEffect, read this blogpost by Dan Abramov (it’s looong): https://overreacted.io/a-complete-guide-to-useeffect/