Background
Recently I saw a question on Stackoverflow where the poster was looking to run a useEffect
in debounced manner.
Here is a screenshot:
This makes sense as many times as there are situations where some effects need to run but not on every change to a dependency. Eg: In a type search bar which makes API calls, we can run useEffect
in a debounced manner to optimise resource utilisation.
I tried to have a go at the answer and tried making a custom hook to solve the problem. I will try to summarise the hook below:
The hook
This is the basic structure we know our custom hook would follow:
const useDebounceEffect = (fnc, deps, delay) => {
useEffect(() => {
},deps);
}
In addition to the params of the standard useEffect, this will have a delay
parameter too. The hook internally will still use useEffect
.
We will need to use a setTimeout
to schedule our callback function. This timeout needs to be cleared too, so it is important to keep the ID of the timeout. We need to have a ref
which holds our timeout ID. State variable is not required here since we do not want to cause a re-render whenever our ID
changes.
const useDebounceEffect = (fnc, deps, delay) => {
const ref = useRef();
useEffect(() => {
clearTimeout(ref.current);
ref.current = setTimeout(() => {
fnc();
clearTimeout(ref.current);
}, delay);
}, deps);
};
The hook looks almost ready, but there is one problem:
The dependencies are not complete. If after a render, fnc
changes or delay
changes, the effect is not triggered.
We get a warning for that from our linter too and we fix it to complete the hook.
const useDebounceEffect = (fnc, deps, delay) => {
const ref = useRef();
useEffect(() => {
clearTimeout(ref.current);
ref.current = setTimeout(() => {
fnc();
clearTimeout(ref.current);
}, delay);
}, [fnc, ...deps,delay]);
};
Note how we do not need to mention ref
in the dependency. ref.current
will always have the correct value since it is a mutable container and changing ref.current
does not cause a rerender.
Links
With this our hook is complete. Here is link to the original question and a running demo
Top comments (0)