-1

I've a setInterval timer in useEffect and I want the timer to start from zero on page refresh. But it's not.

const [timer, setTimer] = useState(0)

useEffect(() => {
    const timer = setInterval(() => {
      const d = new Date(),
        seconds = d.getMinutes() * 60 + d.getSeconds(),
        totalTime = 60 * 6,
        tL = totalTime - (seconds % totalTime),
        r = `${parseInt(tL / 60, 10)}:${tL % 60}`;

     setTimer(r);
}, 1000);
return () => clearInterval(timer);
}, []);
  • What do you mean the timer is not starting from zero? What is it starting from then? How are you observing this? – Dennis Kats Jun 09 '23 at 11:54
  • Hi @DennisKats timer is working fine, but when you refresh it's not starting form 0 instead it starts from where it left at the time of refresh. – fullstack dev Jun 15 '23 at 16:04
  • What exactly are you trying to implement? A 6-minute timer? In essence, your timer preserves its state between refreshes because you are using the browser’s built-in “clock” (`Date`) to determine the time remaining. – Dennis Kats Jun 16 '23 at 07:17
  • @DennisKats any suggestion how to stop this timer on refresh please. – fullstack dev Jun 16 '23 at 09:55

2 Answers2

0

I am not sure how the whole code looks like, but I think you need to do the following adjustments to the code by adding useState, it initializes the timer state to 0 when the component is rendered :

function App = () => {
  const [timer, setTimer] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setTimer(prev => prev + 1);
    }, 1000);
    return () => clearInterval(interval);
  }, []);
dev0717
  • 177
  • 4
0

If you want a simple countdown, you can do something like this (i.e. derive your state from the number of seconds passed):

function App() {
  const [secondsPassed, setSecondsPassed] = React.useState(0);

  const startTime = 60 * 6;
  const timeLeft = startTime - (secondsPassed % startTime);

  const minuteCount = ~~(timeLeft / 60);
  const secondsCount = timeLeft % 60;
  const countdown = `${minuteCount}:${secondsCount.toLocaleString("en-US", {
    minimumIntegerDigits: 2
  })}`;

  React.useEffect(() => {
    const timer = setInterval(() => {
      setSecondsPassed(sp => sp + 1);
    }, 1000);
    return () => clearInterval(timer);
  }, []);

  return <div > {
    countdown
  } < /div>;
}

ReactDOM.createRoot(document.getElementById("root")).render( < App / > );
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>

<div id="root"></div>

However, using setInterval() to increment your timer is actually somewhat of a naive approach because it's not guaranteed to execute immediately after the specified time has passed (if the main thread is busy). The more robust approach is to derive the seconds passed from some start time value like so:

function App() {
  const startNow = React.useMemo(() => Date.now(), []);
  const [now, setNow] = React.useState(startNow);

  const secondsPassed = ~~((now - startNow) / 1000);

  const startTime = 60 * 6;
  const timeLeft = startTime - (secondsPassed % startTime);

  const minuteCount = ~~(timeLeft / 60);
  const secondsCount = timeLeft % 60;
  const countdown = `${minuteCount}:${secondsCount.toLocaleString("en-US", {
    minimumIntegerDigits: 2
  })}`;

  React.useEffect(() => {
    const timer = setInterval(() => setNow(Date.now()), 1000);
    return () => clearInterval(timer);
  }, []);

  return <div > {
    countdown
  } < /div>;
}


ReactDOM.createRoot(document.getElementById("root")).render(<App/>);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>

<div id="root"></div>
Dennis Kats
  • 2,085
  • 1
  • 7
  • 16