I made a timer for a card game and everything was working fine to this point. But I wanted to stop the timer when there's a winner and stop the timer animation by the way. So basically with the following code the when there's a winner the timer will only stop at the end of the current turn before going back to idle state (when value is null).
useEffect(() => {
if (turnTimerStartedAt && !winnerPlayerId) {
const startedAt =
Date.now() - (Rune.gameTimeInSeconds() - turnTimerStartedAt) * 1000;
const tick = () => {
const newValue = MAX_TURN_TIME - (Date.now() - startedAt) / 1000 - 0.5;
if (newValue <= 0) {
setValue(0);
} else {
setValue(newValue);
requestAnimationFrame(tick);
}
};
tick();
} else {
setValue(null);
}
}, [turnTimerStartedAt, winnerPlayerId]);
I want it to stop it as soon as a winnerPlayerId
is set and noticed it doesn't stop when any of the variables (turnTimerStartedAt
or winnerPlayerId
) make the condition falsy.
Is there a way to make the timer stop when the dependencies change ?
You need to cancel the requestAnimationFrame
by assigning the requestId
to a variable, and cancelling the request using cancelAnimationFrame
.
In this case, I would use the cleanup function of useEffect
to cancel the animation frame, whenever the dependencies change:
useEffect(() => {
let requestId;
if (turnTimerStartedAt && !winnerPlayerId) {
const startedAt =
Date.now() - (Rune.gameTimeInSeconds() - turnTimerStartedAt) * 1000;
const tick = () => {
const newValue = MAX_TURN_TIME - (Date.now() - startedAt) / 1000 - 0.5;
if (newValue <= 0) {
setValue(0);
} else {
setValue(newValue);
requestId = requestAnimationFrame(tick); // set the requestId
}
};
tick();
} else {
setValue(null);
}
return () => {
cancelAnimationFrame(requestId); // cancel the animation frame
};
}, [turnTimerStartedAt, winnerPlayerId]);