0

I want to create a reverse timer on button click.

I created a setInterval with a function that should take into account the data of seconds and minutes, and when you click on the start button, seconds = 59 and decrease by 1 every second, after that, when seconds = 0, minutes should decrease by 1, and seconds are 59. But after pressing the button, seconds = 59 and minutes -1, but no countdown occurs

  const [time, setTime] = useState(10);
  const [sec, setSec] = useState(0);
  const [min, setMin] = useState(10);

  let timerInt;

  const timer=()=> {
    timerInt = setInterval(timerF, 1000);
    function timerF() {
      if(sec===0){
        setSec(59);
        setMin(min - 1);
      }
      if (sec <= 0 && min <= 0) {
        clearInterval(timerInt);
        setSec(0);
        setMin(0);
        console.log('finish')
      }
      setSec(prev=>prev-1)
    }
  }
  const handleStart = (time) => {
    setMin(time)
    setTime(time)
    timer();
    setDisabledBtn(true);
  };
      <div className="time">
        <div className="time-min">{min}</div>
        <span>:</span>
        <div className="time-sec">{sec}</div>
      </div>
      <button
        className="start-btn active-btn"
        type="button"
        disabled={disabledBtn && 'disabled'}
        onClick={() => handleStart(10)}
      >
        START
      </button>
wch
  • 276
  • 4
  • 16

1 Answers1

1

In your case the setInterval does not have the updated react state value. So i have created similar functionality using the useEffect and calling the timer() function with the updated react state. I have used setTimeout because we are binding and clearing the setTimeout on every state update. So there is no point using setInterval in my use-case.

Updated and working code below:

import React, {useState, useEffect} from 'react';

export function App(props) {
   const [time, setTime] = useState(2);
  const [sec, setSec] = useState(0);
  const [min, setMin] = useState(2);
  const [startTimer, setStartTimer] = useState(false);

  let timerInt;

  useEffect(() => {
    if(startTimer) {
      timer();
    }
    return () => {
      clearTimeout(timerInt);
    }
  }, [min, sec, startTimer]);

  const timer = () => {

    const timerF = () => {
      console.log("timer1", sec, min);
      if(!sec){
        setSec(59);
        setMin(min - 1);
      }
      if (sec <= 0 && min <= 0) {
        clearTimeout(timerInt);
        setSec(0);
        setMin(0);
        setStartTimer(false);
        console.log('finish')
      }
      setSec(prev=>prev-1)
    }
    timerInt = setTimeout(timerF, 1000);
  }

  const handleStart = (time) => {
    setStartTimer(true);
    setMin(time)
    setTime(time);
  };
   return (
    <div>
    <div className="time">
        <div className="time-min">{min}</div>
        <span>:</span>
        <div className="time-sec">{sec}</div>
    </div>
      <button
        className="start-btn active-btn"
        type="button"
        onClick={() => handleStart(2)}
      >
        START
      </button>
      </div>
   )

}

Try it out and let me know if you still have questions/concerns.

Incoglee
  • 26
  • 3
  • I modified it a little, because at the end when the countdown ended in the seconds field on the screen it was -1. I fixed it and everything works as it should! Thank you! – wch May 09 '23 at 16:10