I tried coding a countdown timer as follows.
Every second the getTime() function is called. In this function, I have a variable named finishhours and a variable named currentHours. Finishhours is equal to the time that the countdown timer should be zero. CurrentHours is equal to the current time.
To make calculations easier I format both variables in hours. For example, 10:45:32 will bee 10 + 45/60 + 32/3600 = 10,76.
From there I can calculate the remaining hours, minutes and seconds and assign these values to variables: rHour, rMin and rSec. These 3 variables are then used to display the remaining time on the screen.
The problem I am facing is that the function getTime() gets called multiple times every second. And the number of times it gets called increases exponentially. For example, after one second elapses the function is called 2 times, one second later the function is called 8 times, then 32 times, and so on.
This is my code:
import React, { useState } from 'react';
import '../Timer.css';
const startDate = new Date();
const Timer = ({ end }) => {
const[rHour, setRHour] = useState(2); //countdown 2 hours.
const[rMin, setRMin] = useState(0);
const[rSec, setRSec] = useState(0);
function getTime(){
const finishHours = startDate.getHours() + 2 + startDate.getMinutes() / 60 + startDate.getSeconds() / 3600;
const currentHours = new Date().getHours() + new Date().getMinutes() / 60 + new Date().getSeconds() / 3600;
const remainingHours = finishHours - currentHours;
const remainingHour = Math.floor(remainingHours);
const remainingMinute = Math.floor((remainingHours - remainingHour) * 60);
const remainingSecond = Math.floor(((remainingHours - remainingHour) * 60 - remainingMinute)*60)
setRHour(remainingHour);
setRMin(remainingMinute);
setRSec(remainingSecond);
console.log("count")
}
setInterval(function(){
getTime()
}, 1000);
return(
<div className="timer-container">
<div className="numbers">
<span className = "num-span">{("0" + rHour).slice(-2)}</span>
<span className = "segment">:</span>
<span className = "num-span">{("0" + rMin).slice(-2)}</span>
<span className = "segment">:</span>
<span className = "num-span">{("0" + rSec).slice(-2)}</span>
</div>
<div class="sub-numbers">
<span className = "sub-span">Uur</span>
<span></span>
<span className = "sub-span">Min</span>
<span></span>
<span className = "sub-span">Sec</span>
</div>
</div>
);
};
export {Timer};
Is there a way I can prevent this? Thank you in advance.
I tried coding a countdown timer as follows.
Every second the getTime() function is called. In this function, I have a variable named finishhours and a variable named currentHours. Finishhours is equal to the time that the countdown timer should be zero. CurrentHours is equal to the current time.
To make calculations easier I format both variables in hours. For example, 10:45:32 will bee 10 + 45/60 + 32/3600 = 10,76.
From there I can calculate the remaining hours, minutes and seconds and assign these values to variables: rHour, rMin and rSec. These 3 variables are then used to display the remaining time on the screen.
The problem I am facing is that the function getTime() gets called multiple times every second. And the number of times it gets called increases exponentially. For example, after one second elapses the function is called 2 times, one second later the function is called 8 times, then 32 times, and so on.
This is my code:
import React, { useState } from 'react';
import '../Timer.css';
const startDate = new Date();
const Timer = ({ end }) => {
const[rHour, setRHour] = useState(2); //countdown 2 hours.
const[rMin, setRMin] = useState(0);
const[rSec, setRSec] = useState(0);
function getTime(){
const finishHours = startDate.getHours() + 2 + startDate.getMinutes() / 60 + startDate.getSeconds() / 3600;
const currentHours = new Date().getHours() + new Date().getMinutes() / 60 + new Date().getSeconds() / 3600;
const remainingHours = finishHours - currentHours;
const remainingHour = Math.floor(remainingHours);
const remainingMinute = Math.floor((remainingHours - remainingHour) * 60);
const remainingSecond = Math.floor(((remainingHours - remainingHour) * 60 - remainingMinute)*60)
setRHour(remainingHour);
setRMin(remainingMinute);
setRSec(remainingSecond);
console.log("count")
}
setInterval(function(){
getTime()
}, 1000);
return(
<div className="timer-container">
<div className="numbers">
<span className = "num-span">{("0" + rHour).slice(-2)}</span>
<span className = "segment">:</span>
<span className = "num-span">{("0" + rMin).slice(-2)}</span>
<span className = "segment">:</span>
<span className = "num-span">{("0" + rSec).slice(-2)}</span>
</div>
<div class="sub-numbers">
<span className = "sub-span">Uur</span>
<span></span>
<span className = "sub-span">Min</span>
<span></span>
<span className = "sub-span">Sec</span>
</div>
</div>
);
};
export {Timer};
Is there a way I can prevent this? Thank you in advance.
Share Improve this question asked Jul 14, 2021 at 13:05 M.DeBaeckeM.DeBaecke 832 silver badges10 bronze badges 2- Can you please put a log in first line of Timer function. Timer function might be call multiple time rather then just getTime() – Mayur Kukadiya Commented Jul 14, 2021 at 13:09
- 1 Your setInterval wants to be inside a useEffect.. – Keith Commented Jul 14, 2021 at 13:10
3 Answers
Reset to default 2Basically every render you are doing is creating a new setInterval, you only want a single setInterval when the ponent is mounted.
For things like this you want to use useEffect
, useEffect also has a callback method you can use to clean up the setInterval when the ponent is unmounted.
So using this information.
try>
useEffect(() => {
const i = setInterval(getTime, 1000);
return () => clearInterval(i);
}, [end]); //dependency, if end changes remount
You should set the interval in a useEffect
. As on each setstate
the ponent is being re-rendered and setting the interval again.
useEffect(()=>{
setInterval(()=>{
getTime()
}, 1000);
},[]);
Try this code : UseEffect
will set this interval once even Timer function call multiple time. then after setInterval will call again and again.
import React, { useState } from 'react';
import '../Timer.css';
const startDate = new Date();
const Timer = ({ end }) => {
const[rHour, setRHour] = useState(2); //countdown 2 hours.
const[rMin, setRMin] = useState(0);
const[rSec, setRSec] = useState(0);
function getTime(){
const finishHours = startDate.getHours() + 2 + startDate.getMinutes() / 60 + startDate.getSeconds() / 3600;
const currentHours = new Date().getHours() + new Date().getMinutes() / 60 + new Date().getSeconds() / 3600;
const remainingHours = finishHours - currentHours;
const remainingHour = Math.floor(remainingHours);
const remainingMinute = Math.floor((remainingHours - remainingHour) * 60);
const remainingSecond = Math.floor(((remainingHours - remainingHour) * 60 - remainingMinute)*60)
setRHour(remainingHour);
setRMin(remainingMinute);
setRSec(remainingSecond);
console.log("count")
}
useEffect(()=>{
setInterval(function(){
getTime()
}, 1000);
}, []);
return(
<div className="timer-container">
<div className="numbers">
<span className = "num-span">{("0" + rHour).slice(-2)}</span>
<span className = "segment">:</span>
<span className = "num-span">{("0" + rMin).slice(-2)}</span>
<span className = "segment">:</span>
<span className = "num-span">{("0" + rSec).slice(-2)}</span>
</div>
<div class="sub-numbers">
<span className = "sub-span">Uur</span>
<span></span>
<span className = "sub-span">Min</span>
<span></span>
<span className = "sub-span">Sec</span>
</div>
</div>
);
};
export {Timer};