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
hooks.
However, there are some issues with using useDebounce
in a resize event.
useDebounce hook
must be run on top of the component because it uses useEffect internally.
However, the resize function is set up to run on useEffect as shown below.
Also, the above code takes the value as a factor, but I think we need to receive it as a callback to use the code below.
useEffect(() => { const handler = () => { if (liRef.current) setWidth(liRef.current.clientWidth); }; window.addEventListener('resize', handler); return () => window.removeEventListener('resize', handler); }, []);
How to use the above code to take advantage of the existing useDebounce?
If you use the debounced function directly in the React component, it will not work because a new function will be created for each render. Instead, you can use this
useDebounce
hook:useRef
ensures that it is the same function as the last one provided, anduseLayoutEffect
ensures that on every render, the reference to the function is updated.For more information on this, see "Latest Reference" Pattern Reaction
I think that instead of implementing debounce through
useEffect
, it is better to implement the debounce logic as a function.useEffect
Executed when the state referenced bydeps
changes. In other words, since it is a logic that is easily missed if you only follow the execution process, it is difficult to figure out which process thisuseEffect
is derived from during later maintenance, and it is also difficult to debug.Example
Customized debounce
If you use
lodash
, you can just import to use it.Lodash Debounce
Hope this helps :)