useDebounce
Use a debounced callback.
API
function useDebounce<T extends (...args: any[]) => any>(
callback: T,
options?: number | { wait?: number; maxWait?: number; leading?: boolean; trailing?: boolean },
): [
debouncedCallback: (...args: Parameters<T>) => ReturnType<T> | undefined,
actions: {
flush: () => ReturnType<T> | undefined;
cancel: () => void;
},
];
Parameters:
callback: Original callback function.options: Debounce wait time or an options object.options.wait: Debounce wait time, in milliseconds. Default is0.options.maxWait: Max wait time, in milliseconds. Default isInfinity.options.leading: Run callback on the leading edge. Default isfalse.options.trailing: Run callback on the trailing edge. Default istrue.
Results:
debouncedCallback: Debounced callback.actions: Actions object.actions.flush: Flush function. Run callback immediately.actions.cancel: Cancel debounce timer.
Notes
- The pending trailing invocation is cancelled on unmount — it never runs.
- Changing the options mid-flight immediately flushes the pending invocation of the old debounced function.
- The returned function returns
undefinedwhen the invocation is deferred. - With
leading: falseandtrailing: false, the callback never runs.
Example
The following example shows how many times the callback actually runs after clicking the button rapidly.
Callback actually runs: 0
import { useRef, useState } from "react";
import { useDebounce } from "@lilib/hooks";
function Example() {
const callsRef = useRef(0);
const [runs, setRuns] = useState(0);
const [debouncedCall] = useDebounce(
() => {
callsRef.current++;
setRuns(callsRef.current);
},
{ wait: 500 },
);
return (
<>
<div>
<button onClick={() => debouncedCall()}>Debounced call</button>
</div>
<div>Callback actually runs: {runs}</div>
</>
);
}
export default Example;