Happy 2k22! I am building a countdown timer. I have two files. The first file takes the countDown time from input
and the second from select dropdown
.
I have implemented an increment
button in the first file. It increases the countDown time by inc
seconds i.e. time = time + inc
.
So what's peculiar?
Thing is that when inc
is replaced with any constant value, it works properly.
<button onClick={() => setSecondsRemaining(secondsRemaining + 3)}>
Increment {inc} sec
</button>
But when I used the input to enter the value and supply it through the variable inc
, then it does not work. It increases randomly.
<button onClick={() => setSecondsRemaining(secondsRemaining + inc)}>
Increment {inc} sec
</button>
You can visit InputCountDown.js
here
This is the full code:
import React, { useState, useEffect, useRef } from "react";
import "./styles.css";
const STATUS = {
STARTED: "Started",
STOPPED: "Stopped"
};
export default function InputCountDown() {
const [time, setTime] = useState(0);
const [inc, setInc] = useState(0);
const handleOnChange = (e) => {
//console.log(e.target.value);
setTime(e.target.value);
};
const handleOnChangeIncrement = (e) => {
console.log(e.target.value);
setInc(e.target.value);
};
const [secondsRemaining, setSecondsRemaining] = useState(time * 60);
//console.log(time);
const [status, setStatus] = useState(STATUS.STOPPED);
const secondsToDisplay = secondsRemaining % 60;
const minutesRemaining = (secondsRemaining - secondsToDisplay) / 60;
const minutesToDisplay = minutesRemaining % 60;
const hoursToDisplay = (minutesRemaining - minutesToDisplay) / 60;
const handleStart = () => {
setStatus(STATUS.STARTED);
setSecondsRemaining(time * 60);
};
const handleStop = () => {
setStatus(STATUS.STOPPED);
};
const handleReset = () => {
setStatus(STATUS.STOPPED);
setSecondsRemaining(time * 60);
};
useInterval(
() => {
if (secondsRemaining > 0) {
setSecondsRemaining(secondsRemaining - 1);
} else {
setStatus(STATUS.STOPPED);
}
},
status === STATUS.STARTED ? 1000 : null
// passing null stops the interval
);
return (
<>
<div className="App">
<h1>Countdown Using Input</h1>
<div style={{ padding: "12px" }}>
<label htmlFor="time"> Enter time in minutes </label>
<input
type="text"
id="time"
name="time"
value={time}
onChange={(e) => handleOnChange(e)}
/>
</div>
<div style={{ padding: "12px" }}>
<label htmlFor="inc"> Enter increment </label>
<input
type="text"
id="inc"
name="inc"
value={inc}
onChange={(e) => handleOnChangeIncrement(e)}
/>
</div>
<button onClick={handleStart} type="button">
Start
</button>
<button onClick={handleStop} type="button">
Stop
</button>
<button onClick={handleReset} type="button">
Reset
</button>
<div style={{ padding: 20, fontSize: "40px" }}>
{twoDigits(hoursToDisplay)}:{twoDigits(minutesToDisplay)}:
{twoDigits(secondsToDisplay)}
<div>
<button onClick={() => setSecondsRemaining(secondsRemaining + inc)}>
Increment {inc} sec
</button>
</div>
</div>
<div>Status: {status}</div>
</div>
</>
);
}
// source: https://overreacted.io/making-setinterval-declarative-with-react-hooks/
function useInterval(callback, delay) {
const savedCallback = useRef();
// Remember the latest callback.
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
let id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
}
// https://stackoverflow.com/a/2998874/1673761
const twoDigits = (num) => String(num).padStart(2, "0");
You can visit InputCountDown.js
here
Please help me.