Reputation: 23
I'm trying to build a timer witch is triggered by one button with function handleToggle, which looks like:
const handleToggle = () => {
let timer = () => setInterval(() => {
dispatch({ type: "COUNT", payload: Date.now() - startTime });
}, 100);
const startTime = Date.now() - AppState.runningTime;
if (AppState.countingStarted) {
dispatch({
type: "COUNTING_STARTED",
payload: false
});
clearInterval(timer());
} else {
timer()
dispatch({ type: "COUNTING_STARTED", payload: true });
}
};
COUNTING_STARTED is a dispatch function which toggles AppState.countingStarted.
I'm struggling with stopping a timer, how to clear that timer-Interval? I tried:
const handleToggle = () => {
let timer;
if (AppState.countingStarted) {
dispatch({
type: "COUNTING_STARTED",
payload: false
});
clearInterval(timer);
} else {
timer = setInterval(() => {
dispatch({ type: "COUNT", payload: Date.now() - startTime });
}, 100);
const startTime = Date.now() - AppState.runningTime;
dispatch({ type: "COUNTING_STARTED", payload: true });
}
};
but there is no difference...
Upvotes: 1
Views: 1126
Reputation: 18113
In your example, the reference to the intervalId
is lost at the end of the function execution.
You should use an instance variable to store the intervalId. If you have a Class
component you can use the following code :
handleToggle = () => {
// clear the interval, no matter the value of AppState.countingStarted
// this prevent from recreating the interval multiple times
clearInterval(this.timerId);
if (AppState.countingStarted) {
dispatch({type: "COUNTING_STARTED",payload: false});
} else {
// store the timer id in an instance variable
this.timerId = setInterval(() => {
dispatch({ type: "COUNT", payload: Date.now() - startTime });
}, 100);
dispatch({ type: "COUNTING_STARTED", payload: true });
}
If you are in a Function
component, you can use the hook useRef to get the same behavior :
const timerIdRef = useRef(null);
const handleToggle = () => {
clearInterval(timerIdRef.current);
if (AppState.countingStarted) {
dispatch({type: "COUNTING_STARTED",payload: false});
} else {
// store the interval id into the current property
timerIdRef.current = setInterval(() => {
dispatch({ type: "COUNT", payload: Date.now() - startTime });
}, 100);
dispatch({ type: "COUNTING_STARTED", payload: true });
}
Upvotes: 2
Reputation: 2652
A couple of things: what you pass to clearInterval
has to be the return value from setInterval
; in the first example you are passing your own function to it. The second example has this right, but you're storing the timer
(the result of calling setInterval
) in the scope of the toggle function, which means once the function completes, you lose the reference to it; the next time you call the function (e.g. to stop it), you re-define timer
, which is not what you want.
All you need is to keep the timer
variable in a scope where it will persist. For example:
let timer = null;
const handleToggle = () => {
if (AppState.countingStarted) {
dispatch({
type: "COUNTING_STARTED",
payload: false
});
clearInterval(timer);
} else {
timer = setInterval(() => {
dispatch({ type: "COUNT", payload: Date.now() - startTime });
}, 100);
const startTime = Date.now() - AppState.runningTime;
dispatch({ type: "COUNTING_STARTED", payload: true });
}
};
This function can be called multiple times; the timer
variable will persist throughout.
Upvotes: 0