I've been searching for an answer to this question for long, however no one here has been able to give me a clear answer yet.
I've got a timer (shown below), however, instead of stopping at 0, the timer instead starts counting down from 24 hours.
Does anyone have any idea how I can stop this timer and zero? Also, the useEffect keeps running like crazy and I'd really appreciate it if someone can help me out with that as well.
Thanks!
CODE:
import { create } from 'domain';
import React, { useState, useRef, useEffect } from 'react'
import { useMoralisQuery } from "react-moralis";
//stop useEffect from running infinitely
const Timer = ({time, createdAt}) => {
const Ref = useRef(null);
const [timer, setTimer] = useState('00:00:00');
const [timerOn, setTimerOn] = useState(false)
const number = 1000
const getTimeRemaining = (e) => {
var total = (Date.parse(e) - Date.parse(new Date())) / 1000;
var days = Math.floor(total / 86400);
total -= days * 86400;
var hours = Math.floor(total / 3600) % 24;
total -= hours * 3600;
var minutes = Math.floor(total / 60) % 60;
total -= minutes * 60;
var seconds = total % 60;
var now = Date.parse(new Date()) / 1000
var timeP = (Date.parse(createdAt) / 1000) + time
// console.log(timeP)
// console.log(now)
return {
total, days, hours, minutes, seconds, now, timeP
};
}
const startTimer = (e) => {
let { total, days, hours, minutes, seconds, now, timeP }
= getTimeRemaining(e);
if (now < timeP) { //try total > now
setTimer(
(days < 1 ? '00' : days) + ':' +
(hours > 9 ? hours : '0' + hours) + ':' +
(minutes > 9 ? minutes : '0' + minutes) + ':'
+ (seconds > 9 ? seconds : '0' + seconds)
)
}
if (now > timeP) {
setTimer('00:00:00')
}
}
const clearTimer = (e) => {
setTimer('00:00:00');
if (Ref.current) clearInterval(Ref.current);
const id = setInterval(() => {
startTimer(e);
}, 1000)
Ref.current = id;
}
const getDeadTime = () => {
let deadline = new Date(createdAt);
deadline.setSeconds(deadline.getSeconds() + Math.floor(time));
return deadline;
}
useEffect(() => {
clearTimer(getDeadTime());
}, []);
const onClickReset = () => {
clearTimer(getDeadTime());
}
return (
<div className="App">
<h2 className='text-3xl lg:text-4xl text-themeYellow bg-clip-text text-center bg-black'>{timer}</h2>
</div>
)
}
export default Timer;
PS: I got the code from here: https://www.geeksforgeeks.org/how-to-create-a-countdown-timer-using-reactjs/
Hmmm...can't seem to pinpoint the exact cause of your bug. However if your question is how to build a countdown timer, this is how I'd approach it.
const [days, setDays] = React.useState('00');
const [hours, setHours] = React.useState('00');
const [minutes, setMinutes] = React.useState('00');
const [seconds, setSeconds] = React.useState('00');
React.useEffect(() => {
//@: get the time in milliseconds towards the due date
const dueDate = new Date("Jan 15, 2023 00:00:00").getTime();
//@: create an interval to countdown every 1 sec
const timerInterval = setInterval(() => {
//@: get the current date in milliseconds
const now = new Date().getTime();
//@: calculate the time elapsed by subtracting the due date by the current date
const timeElapsed = dueDate - now;
//@: get the remaining days, hours, minutes and secs from the time elapsed calculated above
const dd = Math.floor(timeElapsed / (1000 * 60 * 60 * 24));
const hh = Math.floor((timeElapsed % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const mm = Math.floor((timeElapsed % (1000 * 60 * 60)) / (1000 * 60));
const ss = Math.floor((timeElapsed % (1000 * 60)) / 1000);
//@: if the time elapsed is less than 0, it means you've passed the due date so clear the interval and stop the timer.
//@: else set the timers accordingly
if(timeElapsed < 0){
clearInterval(timerInterval);
}
else{
setDays(dd);
setHours(hh);
setMinutes(mm);
setSeconds(ss);
}
}, 1000);
//@: cleanup function to clear any intervals once this component unmounts
return () => {
clearInterval(timerInterval);
}
}, []);
<div>{days} days : {hours} hours : {minutes} mins : {seconds} secs</div>
You could take this a step further by encapsulating this whole logic within a component called Countdown which takes in a date string prop. So it would look like this.
const Countdown = ({releaseDate}) => {
const [days, setDays] = React.useState<string | number>('00');
const [hours, setHours] = React.useState<string | number>('00');
const [minutes, setMinutes] = React.useState<string | number>('00');
const [seconds, setSeconds] = React.useState<string | number>('00');
React.useEffect(() => {
const dueDate = new Date(releaseDate).getTime();
const timerInterval = setInterval(() => {
const now = new Date().getTime();
const timeElapsed = dueDate - now;
const dd = Math.floor(timeElapsed / (1000 * 60 * 60 * 24));
const hh = Math.floor((timeElapsed % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const mm = Math.floor((timeElapsed % (1000 * 60 * 60)) / (1000 * 60));
const ss = Math.floor((timeElapsed % (1000 * 60)) / 1000);
if(timeElapsed < 0){
clearInterval(timerInterval);
}
else{
setDays(dd);
setHours(hh);
setMinutes(mm);
setSeconds(ss);
}
}, 1000);
return () => {
clearInterval(timerInterval);
}
}, [releaseDate]);
return (
<div>{days} days : {hours} hours : {minutes} mins : {seconds} secs</div>
)
}
Then call the component in whatever page you need it like so;
<Countdown releaseDate="Jan 15, 2023 00:00:00" />
Hopefully that helps :)