new to react here. I'm trying to output a countdown timer to a date that is set to 5 minutes from now. But all I was able to get was either the countdown rubber banding, or static on 5 minutes or 0. Currently, it is static on 00:00:00:00. Thanks
EDIT: I'm trying to make it work with hooks instead of through a constructor class.
import AButton from './aButton'; import { useState, useRef, useEffect} from 'react';
export default function Countdown() {
const [addTime, setAddtime] = useState();
const [countdown, setCountdown] = useState((new Date()).toLocaleTimeString());
const [timerDays, setDays] = useState('00');
const [timerHours, setHours] = useState('00');
const [timerMinutes, setMinutes] = useState('00');
const [timerSeconds, setSeconds] = useState('00');
let interval = useRef();
const oldDateObject = new Date();
const sourceDate = oldDateObject.getTime(); // date - 300000
const diff = 5;
//this gives use the unix timestamp of the future date which is the current date + 5 minutes
const futureDate = new Date(oldDateObject.getTime() + diff*60000); //300000
const convertToDate = (date, hours, minutes, seconds) => {
date = new Date(sourceDate * 1000);
// Hours part from the timestamp
hours = date.getHours();
// Minutes part from the timestamp
minutes = ("0" + date.getMinutes()).substr(-2);
// Seconds part from the timestamp
seconds = ("0" + date.getSeconds()).substr(-2);
return hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);
}
const startTimer = () => {
const timeUpdate = new Date().getTime(convertToDate);
interval = setInterval(() => {
const now = new Date().getTime();
const timeDifference = timeUpdate - now;
//this converts the unix code of the future date to each clock element every second
const days = Math.floor(timeDifference / (24 * 60 * 60 * 1000));
const hours = Math.floor(timeDifference % (24 * 60 * 60 * 1000) / (60 * 60 * 1000));;
const minutes = Math.floor(timeDifference % (60 * 60 * 1000) / (60 * 1000));;
const seconds = Math.floor(timeDifference % (60 * 1000) / 1000);;
if (timeDifference < 0) {
clearInterval(interval.current);
} else {
setDays(days);
setHours(hours);
setMinutes(minutes);
setSeconds(seconds);
}
}, 1000);
};
useEffect(() => {
startTimer();
return () => { clearInterval(interval.current);
};
});
return (
<div>
<h1>{countdown === null ? <span style={{padding: '50px'}}></span> : countdown}</h1>
<button onClick={ () => setCountdown(countdown !== null ? null : ( new Date()).toLocaleTimeString())}>{countdown === null ? 'Show' : 'Hide'}</button>
<div>----------------</div>
<h1>{timerDays} : {timerHours} : {timerMinutes} : {timerSeconds}</h1>
<button>Activate countdown</button>
</div>
)
}
I think you are making it way more complicated than it needs to be.
Store a state of a 5 minute countdown (in seconds) and a second piece of state to start/run the timer.
When the timer is started seed the countdown state with 5 minutes (it will expire from the current point in time).
Compute the derived and formatted time from the single countdown state.
function App() {
const [countDown, setCountDown] = React.useState(0);
const [runTimer, setRunTimer] = React.useState(false);
React.useEffect(() => {
let timerId;
if (runTimer) {
setCountDown(60 * 5);
timerId = setInterval(() => {
setCountDown((countDown) => countDown - 1);
}, 1000);
} else {
clearInterval(timerId);
}
return () => clearInterval(timerId);
}, [runTimer]);
React.useEffect(() => {
if (countDown < 0 && runTimer) {
console.log("expired");
setRunTimer(false);
setCountDown(0);
}
}, [countDown, runTimer]);
const togglerTimer = () => setRunTimer((t) => !t);
const seconds = String(countDown % 60).padStart(2, 0);
const minutes = String(Math.floor(countDown / 60)).padStart(2, 0);
return (
<div className="App">
<div>
Time: {minutes}:{seconds}
</div>
<button type="button" onClick={togglerTimer}>
{runTimer ? "Stop" : "Start"}
</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<App />,
rootElement
);
.App {
font-family: sans-serif;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>