Photo by George Bakos on Unsplash
useInterval() vs setInterval()
Some subtleties only come with Time...
There is a difference other than spelling.
We know that one of the common tasks in web development is to update the state of a component at regular intervals, such as updating a clock, displaying a slideshow, or polling for new data. This can be achieved by using the setInterval
function.
setInterval
is a JavaScript function that runs a function repeatedly, at specified intervals called 'delays'.
You can use setInterval to update a clock component every second:
import React, { useState, useEffect } from 'react';
const Clock = () => {
const [time, setTime] = useState(new Date());
useEffect(() => {
const intervalId = setInterval(() => {
setTime(new Date());
}, 1000);
return () => clearInterval(intervalId);
}, []);
return
<div>{time.toLocaleTimeString()}</div>;
};
export default Clock;
In this code, the useEffect
hook is used to create an interval that updates the time state every second. The return statement in the useEffect
callback is used to clean up the interval when the component is unmounted, to avoid memory leaks.
However, there is a problem with using setInterval
in this way. If the component re-renders due to changes in state or props, the interval will keep running, even if the component is not visible on the screen. This can have negative impacts on performance and battery life, and sometimes your sanity when you don't know where the bug is coming from.
To address this issue, you can create a custom hook called useInterval
that only runs the interval when the component is mounted and clears the interval when the component is unmounted. The useInterval
hook also allows you to control the interval rate by passing in a delay parameter.
Here's an example:
Make a file separate called useInterval.js
. It is not necessary but is best for modularity.
import React, { useEffect, useRef } from 'react';
const useInterval = (callback, delay) => {
const savedCallback = useRef();
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
const tick = () => {
savedCallback.current();
};
if (delay !== null) {
const id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
};
export default useInterval;
And then use it in your React project, like this:
import React, { useState } from 'react';
import useInterval from './useInterval'
const Clock = ({ delay }) => {
const [time, setTime] = useState(new Date());
useInterval(() => {
setTime(new Date());
}, delay);
return <div>{time.toLocaleTimeString()}</div>;
};
export default Clock;
In this code, the useInterval
hook accepts a callback and a delay parameter, and returns a clean-up function that clears the interval when the component is unmounted. The useEffect
hook inside the useInterval
hook uses a savedCallback
ref to save the callback function between re-renders, and create or clear the interval based on the delay parameter.
By using the useInterval
hook, you can control when the interval runs and when it stops, improving performance and preserving battery life. You can also adjust the interval rate dynamically by passing in a different delay value. This makes "useInterval" a more flexible and efficient solution for managing intervals in React compared to the traditional "setInterval" function.
So basically, "setInterval" may be a useful JavaScript function for running a function repeatedly at specified intervals but, using it directly in React can lead to performance and memory issues, simply because of the way React functions.
The "useInterval" hook solves these issues by providing better control over the interval and allowing for dynamic updates to the interval rate. When building time-based components in React, consider using "useInterval" instead of setInterval for a more optimized solution, or I'll steal all your teeth when you go to sleep.