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?
P粉0984172232024-01-29 11:40:03
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:
function useDebounce(callback, delay) { const callbackRef = React.useRef(callback) React.useLayoutEffect(() => { callbackRef.current = callback }) return React.useMemo( () => debounce((...args) => callbackRef.current(...args), delay), [delay], ) }
useRef
ensures that it is the same function as the last one provided, and useLayoutEffect
ensures that on every render, the reference to the function is updated.
For more information on this, see "Latest Reference" Pattern Reaction
P粉8940084902024-01-29 09:59:42
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 by deps
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 this useEffect
is derived from during later maintenance, and it is also difficult to debug.
Example
Customized debounce
function debounce(func, timeout = 300) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => { func.apply(this, args); }, timeout); }; }
function saveInput() { console.log('Saving data'); } const processChange = debounce(() => saveInput());
If you use lodash
, you can just import to use it.
Lodash Debounce
import { debounce } from 'lodash';
const debounceOnChange = debounce(() => { console.log("This is a debounce function"); }, 500);
Hope this helps :)