this may be a small problem, but it seems that I can't find a solution anywhere. I will try to explain the issue the best way I can.
I have a simple timer function:
let [milliseconds,seconds,minutes] = [0,0,0];
let int = null;
const start = () => {
if(int!==null){
clearInterval(int);
}
int = setInterval(displayTimer,10);
}
const reset = () => {
clearInterval(int);
[milliseconds,seconds,minutes] = [0,0,0];
document.querySelector('.timerDisplay').innerHTML = '00 : 00';
}
function displayTimer(){
milliseconds =10;
if(milliseconds == 1000){
milliseconds = 0;
seconds ;
if(seconds == 60){
seconds = 0;
minutes ;
}
}
let m = minutes < 10 ? "0" minutes : minutes;
let s = seconds < 10 ? "0" seconds : seconds;
document.querySelector('.timerDisplay').innerHTML = `${m} : ${s}`;
}
And when start and reset functionalities are separated in two different buttons, they work like a charm.
<button onClick={reset} id="pauseTimer">Reset</button>
<button onClick={start} id="startTimer">Start</button>
I am encountering an issue when I try to put both of them in a single function, like this:
const newGame = () => {
reset()
//some other code
start()
}
So the newGame
function should (in theory) reset the timer and start the new one. Instead, timer resets to zero for a split second, but the "old one" keeps counting, while the new one starts from 00:00, so the numbers overlap. The more I fire newGame
, the more overlaps I get.
My question is, how do I prevent this?
I've tried using a useState to store the timer, still didn't work.
Thank you!
CodePudding user response:
I cleaned up your code snippets a bit so I could run it on my machine and it appears to run as expected. If you're still seeing a problem on your end it may be in a piece of code that you didn't share that is somehow interfering with the code you shared.
That said, I saw that you mentioned the useState
React hook so I'm assuming you're using React. If that is the case and all of this code is being run inside a React component, then it may be that something you're doing is triggering the component to re-render, which would re-declare new copies of all your local variables and functions. If that's the case, then the reason your old interval is still running is that after the re-render, your reset and start functions are only able to access and interact with the new copies of your local variables that store the current interval and time. I would suggest persisting the state of each of those variables by using the useState
React hook
<html>
<head>
<script>
let [milliseconds, seconds, minutes] = [0, 0, 0];
let int = null;
const start = () => {
if (int !== null) {
clearInterval(int);
}
int = setInterval(displayTimer, 10);
}
const reset = () => {
clearInterval(int);
[milliseconds, seconds, minutes] = [0, 0, 0];
document.querySelector('.timerDisplay').innerHTML = '00 : 00';
}
function displayTimer() {
milliseconds = 10;
if (milliseconds == 1000) {
milliseconds = 0;
seconds ;
if (seconds == 60) {
seconds = 0;
minutes ;
}
}
let m = minutes < 10 ? "0" minutes : minutes;
let s = seconds < 10 ? "0" seconds : seconds;
document.querySelector('.timerDisplay').innerHTML = `${m} : ${s}`;
}
const newGame = () => {
reset()
//some other code
start()
}
</script>
</head>
<body>
<button onClick="reset()" id="pauseTimer">Reset</button>
<button onClick="start()" id="startTimer">Start</button>
<button onClick="newGame()" id="newGame">New Game</button>
<p >00 : 00</p>
</body>
</html>
CodePudding user response:
One solution to this problem is to wrap the start() function in a setTimeout, so that it waits for a short period of time before creating a new interval. This will give the previous interval enough time to fully clear before a new one is created.
const newGame = () => {
reset();
setTimeout(start, 50);
}
This way, the reset() function will have enough time to clear the interval, and the start() function will only be called after a 50 milliseconds delay