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>