import { useEffect, useState } from 'react';
export default function useDebounce(text: string, delay: number) {
const [value, setValue] = useState('');
useEffect(() => {
const timerId = setTimeout(() => {
setValue(text);
}, delay);
return () => {
clearTimeout(timerId);
};
}, [text, delay]);
return value;
}
I used to make and use useDebounce
hook.
However, using useDebounce
in resize event has some problems.
The useDebounce hook
must run at the top of the component because it uses useEffect inside.
However, the resize function is set to run on useEffect as shown below.
Also, the above code takes value as a factor, but I think we need to receive it as callback to use the below code.
useEffect(() => {
const handler = () => {
if (liRef.current) setWidth(liRef.current.clientWidth);
};
window.addEventListener('resize', handler);
return () => window.removeEventListener('resize', handler);
}, []);
How do I use the above code to utilize the existing useDebounce?
2
Answers
I think rather than implementing debounce through
useEffect
, it would be better to implement the debounce logic as a function.UseEffect
is executed when the states referenced bydeps
change. In other words, since it is a logic that can be missed if you only follow the execution flow, it is difficult to figure out which flow thisuseEffect
was derived from when performing maintenance later, and it can be difficult to debug.Example
Custom Debounce
And if you use
lodash
, you can just import to use it.Lodash Debounce
Hope this helps 🙂
If you directly use debounced function inside a react component, it will not work, since a new function will be created on each render, Instead, you can use this
useDebounce
hook:useRef
makes sure that it is the same function provided last time, anduseLayoutEffect
makes sure on each render, the reference to function gets updated.For more info on this, see ‘The Latest Ref’ pattern in React