Timers created with setTimeout
or setInterval
are used often in React apps.
setTimeout
lets us run code after a delay.
And setInterval
lets us run code periodically.
To free up resources and to stop the timers from running, we should call clearTimeout
to stop any timers created with setTimeout
from running.
Likewise, we should call clearInterval
to stop any timers created with setInterval
from running.
In this article, we’ll look at the right way to clear timers created with these functions in React components created with hooks.
Clear Timers Created with setTimeout
To clear timers that are created with setTimeout
, we should call clearTimeout
in the useEffect
callback is the function that’s run when the component unmounts.
The function that we return in the useEffect
callback is run when the component unmounts, so we should put it there,.
For instance, we can write:
import React, { useEffect, useState } from "react";
export default function App() {
const [loading, setLoading] = useState(true);
useEffect(() => {
const timer = setTimeout(() => setLoading(false), 1000);
return () => {
clearTimeout(timer);
};
}, []);
return <div>{loading ? "loading" : "hello"}</div>;
}
We have the loading
state which is initially set to true
.
Then we call useEffect
with a callback.
In the callback, we call setTimeout
with a callback that calls setLoading
with false
to set loading
to false
.
And the callback is run after 1000 milliseconds since the 2nd argument is 1000.
Also, we return a function that calls clearTimeout
with timer
to clear the timer.
This function is run when we unmount the component.
Then we display text according to the value of loading
.
So we should see ‘loading’ first. Then we should see ‘hello’ about 1 second later.
Clear Timers Created with setInterval
Likewise, we can clear a timer created with setInterval
the same way.
For instance, we can write:
import React, { useEffect, useState } from "react";
export default function App() {
const [time, setTime] = useState(0);
useEffect(() => {
const timer = setInterval(() => setTime((t) => t + 1), 1000);
return () => {
clearInterval(timer);
};
}, []);
return <div>{time}</div>;
}
Almost everything is the same except we replaced setTimeout
and clearTimeout
with setInterval
and clearInterval
.
Timers Outside the useEffect Callback
We cal also place timers outside the useEffect
callback.
For instance, we can write:
import React, { useEffect, useRef, useState } from "react";
export default function App() {
const [time, setTime] = useState(0);
const timer = useRef();
useEffect(() => {
timer.current = setInterval(() => setTime((t) => t + 1), 1000);
}, []);
useEffect(() => {
return () => {
clearInterval(timer.current);
};
}, []);
return <div>{time}</div>;
}
We create the timer
ref with the useRef
hook.
Then we set timer.current
to the timer returned by setInterval
.
Then we can call clearInterval
anywhere in our component code.
The same also applies to setTimeout
and clearTimeout
.
Conclusion
We can store our timers in a ref or a variable in the useEffect
callback so we can clear them when we no longer need them.
One reply on “How to Clear Timeout and Interval Timers with React Hooks?”
This code snippet saved us from hours of painful debugging. We were missing the useRef hook to keep track of our timer. The interval object was not getting cleared no matter what.