Home > Back-end >  How to start timer when button pressed? React
How to start timer when button pressed? React

Time:10-24

This is my first project in React (find some tutorial on youtube) and i am a little confused, i am trying to make simple pomodoro timer. Right now count starts when page opens. What i want is to add a little more functionality, like pause/stop the timer buttons, and of course start it when button is pressed. also I would like to add some more things in the future, but at the moment I just want to understand how to make button work

This is how it looks and working fine (without buttons).

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

function App() {
  const [minutes, setMinutes] = React.useState(25);
  const [seconds, setSeconds] = React.useState(0);
  const [displayMessage, setDisplayMessage] = useState(false);

  useEffect(() => {
    let interval = setInterval(() => {
      clearInterval(interval);

      if (seconds === 0) {
        if (minutes !== 0) {
          setSeconds(59);
          setMinutes(minutes - 1);
        } else {
          let minutes = displayMessage ? 24 : 4;
          let seconds = 59;

          setSeconds(seconds);
          setMinutes(minutes);
          setDisplayMessage(!displayMessage);
        }
      } else {
        setSeconds(seconds - 1);
      }
    }, 1000);
    return () => {};
  }, [seconds]);

  const timerMinutes = minutes < 10 ? `0${minutes}` : minutes;
  const timerSeconds = seconds < 10 ? `0${seconds}` : seconds;

  return (
    <div className="timer">
      <h2>
        {timerMinutes}:{timerSeconds}
      </h2>
      <button className="buttons_new">Start</button>
      <button className="buttons_new">Pause</button>
      <button className="buttons_new">Stop</button>
    </div>
  );
}

export default App;

I tried to use some advices from same situations (like using useCallback instead of useEffect, just remove useEffect and make it as normal function) but when i try and add this to button it works only 1 time instead of refreshing every second. So if i click on button time will change from 25:00 to 24:59 and that's all. How can i make it work and dynamically update after clicking the start button? my terrible and stupid attempts below:

const startTimer = () => {
  //same code as above
      <button className="buttons_new" onClick={startTimer}>Start</button>

Also trying to do something like this(effect was the same):

const startTimer = useCallback(() => {

CodePudding user response:

1- Define a state like "continue" and set true or false by onClick event Handler. 2- Put condition inside of use effect to check if counter should continue or not... if(continue){}else{}

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

function App() {
 const [minutes, setMinutes] = React.useState(25);
 const [seconds, setSeconds] = React.useState(0);
 const [displayMessage, setDisplayMessage] = useState(false);
 const [continiue, setContiniue] = useState(false);

useEffect(() => {
 if(coninue){
let interval = setInterval(() => {
  clearInterval(interval);

  if (seconds === 0) {
    if (minutes !== 0) {
      setSeconds(59);
      setMinutes(minutes - 1);
    } else {
      let minutes = displayMessage ? 24 : 4;
      let seconds = 59;

      setSeconds(seconds);
      setMinutes(minutes);
      setDisplayMessage(!displayMessage);
    }
  } else {
    setSeconds(seconds - 1);
  }
}, 1000);

}, [seconds])}};

const timerMinutes = minutes < 10 ? `0${minutes}` : minutes;
const timerSeconds = seconds < 10 ? `0${seconds}` : seconds;


 return (
<div className="timer">
  <h2>
    {timerMinutes}:{timerSeconds}
  </h2>
  <button className="buttons_new" onClick= 
    {()=>setContiniue(!continiue)}>Start</button>
  <button className="buttons_new onClick= 
    {()=>setContiniue(!continiue)}">Pause</button>
  <button className="buttons_new">Stop</button>
</div>
 );
 }

 export default App;

CodePudding user response:

here is what you need to do:

click on run code snippet to see a demo of it

const STATUS = {
    pause: 0,
    start: 1,
    default: 2
  }
function App() {
  const [minutes, setMinutes] = React.useState(25);
  const [seconds, setSeconds] = React.useState(0);
  const [displayMessage, setDisplayMessage] = React.useState(false);
  const [status, setStatus] = React.useState(STATUS.default);
  const intervalRef = React.useRef();
  
  function countDown(){
    if (seconds === 0) {
        if (minutes !== 0) {
          setSeconds(59);
          setMinutes(min => min - 1); // try using callback form to prevent stale data
        } else {
          let mins = displayMessage ? 24 : 4;
          let sec = 59;
          setSeconds(sec);
          setMinutes(mins);
          setDisplayMessage(value => !value);// try using callback form to prevent stale data
        }
      } else {
        setSeconds(sec => sec - 1);// try using callback form to prevent stale data
      }
  }

  React.useEffect(() => {
    if(status === STATUS.start){
      intervalRef.current = setInterval(() => {
        countDown()
      }, 1000);
    } else if(status === STATUS.pause && intervalRef.current){
      clearInterval(intervalRef.current)
    }
    return () => {
      clearInterval(intervalRef.current)
    };
  }, [minutes, seconds, status]);

  const timerMinutes = minutes < 10 ? `0${minutes}` : minutes;
  const timerSeconds = seconds < 10 ? `0${seconds}` : seconds;
  
  const start = () => setStatus(STATUS.start);
  const pause = () => setStatus(STATUS.pause);
  const stop = () => {
    setStatus(STATUS.pause);
    setMinutes(25);
    setSeconds(0);
  }

  return (
    <div className="timer">
      <h2>
        {timerMinutes}:{timerSeconds}
      </h2>
      <button className="buttons_new" onClick={start}>Start</button>
      <button className="buttons_new" onClick={pause}>Pause</button>
      <button className="buttons_new" onClick={stop}>Stop</button>
    </div>
  );
}

ReactDOM.render(<App />, document.querySelector('#root'));
<div id='root'></div>
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related