All questions

useDebounce

Premium

useDebounce

Build a hook that returns a debounced copy of a value. Debouncing means waiting for activity to settle before reacting: as a value changes rapidly, you ignore every intermediate update and only commit once the changes have stopped for a moment. The classic case is a search box — the user types r, re, rea, reac, react, but you only want to fire one search, for react, after they pause. useDebounce(value, delay) gives you that settled value: it mirrors the latest value, but only updates after delay milliseconds have passed with no further changes.

Signature

function useDebounce<T>(value: T, delay: number): T;

The returned value tracks value but lags behind it, updating only after delay ms of quiet.

Examples

function Search() {
  const [text, setText] = useState('');
  const debounced = useDebounce(text, 300);

  // Fires only after the user stops typing for 300ms.
  useEffect(() => {
    if (debounced) fetchResults(debounced);
  }, [debounced]);

  return <input value={text} onChange={(e) => setText(e.target.value)} />;
}
// A burst of changes collapses into a single, final update:
// value:     'r'  're'  'rea'  'reac'  'react'   (then a pause)
// debounced: ''   ''    ''     ''      ''    →   'react'
// Only the LAST value is ever committed; the intermediates are skipped.

Notes

  • The initial value is returned immediately. On the first render there is nothing to wait for, so the hook returns value right away — no delay on mount.
  • Only the last value in a burst survives. If value changes several times faster than delay, the debounced value must skip every intermediate and commit only the final one, once the changes stop.
  • A change resets the clock. Each new value restarts the quiet period from zero; the hook commits only after delay ms with no further change.
  • Falsy values are real values. A new value of '', 0, or false must commit like any other — "no change yet" and "changed to something falsy" are different.
  • Clean up on unmount. A pending update must not fire into a component that has already unmounted.

Unlock the solution & editor

  • Runnable editor + tests

    Solve in the browser with instant Jest feedback.

  • Detailed solutions

    Walkthroughs, edge cases, and complexity notes.

  • Multi-framework variants

    React, Vue, Vanilla, Angular — same question, different stacks.

Upgrade to Premium