All hooks / Timers
useDebouncedCallback
Returns a debounced version of callback: it runs delayMs after the last call, with the arguments of that last call. The returned function is stable and always runs the latest callback, so it can read current state.
A pending call is dropped on unmount (call flush first to keep it) and when delayMs or maxWaitMs change. With maxWaitMs, a burst of calls still runs at least that often.
With Chinese, Japanese, or Korean input, skip calls while e.nativeEvent.isComposing is true and call it in onCompositionEnd, or it runs on half-composed text.
Import
import { useDebouncedCallback } from '@vincent.ri/react-tils'
// or only this hook
import { useDebouncedCallback } from '@vincent.ri/react-tils/useDebouncedCallback'Usage
const search = useDebouncedCallback((query: string) => fetchResults(query), 300)
return <input onChange={(e) => search(e.target.value)} />
// Autosave while typing, at least every 5s, and save on unmount.
const save = useDebouncedCallback(saveDraft, 1000, { maxWaitMs: 5000 })
useEffect(() => () => save.flush(), [save])Live demo
Type quickly: one search after you pause.
When to use it
Search-as-you-type requests, autosaving a draft, or validating an input after the user pauses.
When not to
You only want to keep typing responsive while rendering something expensive; use React's useDeferredValue. To keep running during a burst (live results, sending positions), use useThrottledCallback. For scroll or resize values, prefer the dedicated hooks, which already avoid extra re-renders.
API
function useDebouncedCallback<A extends unknown[]>(callback: (...args: A) => void, delayMs: number, options?: {
maxWaitMs?: number;
}): DebouncedFunction<A>| Parameter | Description |
|---|---|
callback | The function to debounce. Can change every render. |
delayMs | Wait this long after the last call. |
options | maxWaitMs: run at least this often during a burst. Optional. |
Returns The debounced function, with cancel, flush, and pending.
Types
export type DebouncedFunction<A extends unknown[]> = ((...args: A) => void) & {
/** Drop the pending call. */
cancel: () => void;
/** Run the pending call now, if there is one. */
flush: () => void;
/** Whether a call is waiting. Reads it now; doesn't re-render when it changes, so keep state for a "Saving…" label. */
pending: () => boolean;
};Browser support
Uses only long-established browser features, so it works wherever React does.
First version with support, from MDN's compatibility data (web-features 3.42.0, @mdn/browser-compat-data 8.1.5).
Coming from another library?
Other libraries call this useDebounceCallback, useDebounceFn.