Sometimes, we may want to delay or throttle the number of times a piece of code is run in our React component.
In this article, we’ll look at how to throttle or denounce code with React hooks.
Using the Lodash Throttle Function
Lodash comes with the throttle
function to let us limit a function to run once in a given time interval.
For instance, we can write:
import React, { useEffect, useRef, useState } from "react";
import { throttle } from "lodash";
export default function App() {
const [value, setValue] = useState(0);
const throttled = useRef(throttle((newValue) => console.log(newValue), 1000));
useEffect(() => throttled.current(value), [value]);
return <button onClick={() => setValue(value + 1)}>{value}</button>;
}
We call throttle
with the function that we want to run and the time interval in milliseconds.
Therefore, the function runs once every 1000 milliseconds at the maximum.
We put th throttled function in the useRef
hook to set the throttled function as the value of throttled.current
.
This will cache the function between re-renders so it won’t be recreated on every render.
We then call the function we created in the useEffect
callback.
So when we click on the button, we see the throttled
function runs every 1-second max.
Use the useCallback Hook to Store the Throttled Function
We can replace the ref with the useCallback
hook.
For instance, we can write:
import React, { useCallback, useEffect, useState } from "react";
import { throttle } from "lodash";
export default function App() {
const [value, setValue] = useState(0);
const throttled = useCallback(
throttle((newValue) => console.log(newValue), 1000),
[]
);
useEffect(() => throttled(value), [value]);
return <button onClick={() => setValue(value + 1)}>{value}</button>;
}
We just pass in our throttled function into the useCallback
hook to cache the function between re-renders.
And we get the same result as before.
Debouncing Functions
Debouncing functions means we call a function after a delay.
To do this, we can create our own hook by writing:
import React, { useCallback, useEffect, useState } from "react";
const useDebouncedEffect = (effect, delay, deps) => {
const callback = useCallback(effect, deps);
useEffect(() => {
const handler = setTimeout(() => {
callback();
}, delay);
return () => {
clearTimeout(handler);
};
}, [callback, delay]);
};
export default function App() {
const [value, setValue] = useState(0);
useDebouncedEffect(() => console.log(value), 1000, [value]);
return <button onClick={() => setValue(value + 1)}>{value}</button>;
}
We create the useDebouncedEffect
hook by calling setTimeout
in the useEffect
callback.
The callback we call is passed in from the effect
function.
We call useCallback
to cache the effect
function so that it won’t be recreated every time the component is rendered.
deps
has the dependencies we want to watch. When the value changes, useCallback
will recreate the function.
setTimeout
returns a timer object so we can use that to clear it when the component unmounts.
When we unmount the component, we call clearTimeout
to clear the timer.
In App
, we use the useDebouncedEffect
hook with a callback that we want to run after a delay.
Now when we click on the button, we wait 1000 milliseconds until the callback is run.
Conclusion
We can add throttle and denounce easily with React.