2

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(() => {

2 Answers 2

1

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>

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, that's working! :) Although, unfortunately, my knowledge is not enough to write such code myself :( Anyway as i said all working fine and correct, but i find one little bug. If you press stop button when it's a break time - time will set to 25 minutes and message will still remain. I don't know how to fix it yet, but otherwise everything works well. thanks again for your answer and help :)
0

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;

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.