Intro
This is a simple useDebounce React hook. It can be used to debounce a function call with trailing or leading execution.
The code
use-debounce.ts
import { useCallback, useEffect, useRef } from 'react';
type Options =
| { leading?: false; trailing: true; }
| { leading: true; trailing?: false; };
export function useDebounce(fn: Function, ms: number, options?: Options) {
const locked = useRef(false);
const timeout = useRef<ReturnType<typeof setTimeout>>();
const callback = useRef(fn);
useEffect(() => {
callback.current = fn;
}, [fn]);
return useCallback((...params: any) => {
/**
* Trailing execution
* Discard calls to the functon and keep the last one in the timeout
* Execute the last call if the timeout is reached without a new call
*/
if (!options?.leading) {
timeout.current && clearTimeout(timeout.current);
timeout.current = setTimeout(() => {
callback.current(...params);
timeout.current = undefined;
}, ms);
}
/**
* Leading execution
* Execute the callback immediatly
* Discard the following executions until the timeout is reached without a new call
* Unlock the execution when the timeout is reached
*/
if (options?.leading) {
!locked.current && callback.current(...params);
locked.current = true;
timeout.current && clearTimeout(timeout.current);
timeout.current = setTimeout(() => {
locked.current = false;
}, ms);
}
}, [ms]);
};