19. Build a useDebounce Hook — Debounce a Value in React

medium

The most-asked React hooks question. It checks that you truly understand useEffect cleanup — the cleanup is the debounce.

The idea

Mirror the input value into state. Every time value changes, schedule a timeout to copy it into debounced. The effect's cleanup clears the previous timeout, so rapid changes keep cancelling each other until things go quiet for delay ms — then the last value lands.

Why this works

  • The cleanup runs before the next effect, so only the final pending timer survives a burst.
  • delay is in the dependency array, so changing it re-arms correctly.

Follow-ups

  • "Debounce a callback instead of a value?" → useDebouncedCallback wrapping the fn in a useRef'd timer.
  • "Why not store the timer in a useRef here?" → you can, but the effect-cleanup version is the idiomatic one.
  • "Cancel on unmount?" → the same cleanup already handles it.

What to practice

Write useDebounce, then a useDebouncedCallback(fn, delay) variant that returns a stable debounced function.

More questions

index.js
import { useEffect, useState } from "react";

function useDebounce(value, delay = 300) {
  // return a debounced copy of `value`
}

// Usage:
// const debouncedQuery = useDebounce(query, 400);
// useEffect(() => { search(debouncedQuery); }, [debouncedQuery]);

Tests

Test Code

Enter JavaScript that runs after your solution. It should return a value or a Promise.