Debounce vs Throttle in React: Handling Rapid User Input

Debounce waits until rapid events pause before running code, while throttle runs code at most once per interval. Learn both patterns in React.

5 min read

Debounce waits until rapid events pause before running code, while throttle runs code at most once per interval. Debounce is for work that should happen after the user finishes, and throttle is for work that should happen steadily while events fire.

The problem: events fire fast

Typing, scrolling, and resizing fire many events in a short time. Running expensive work on every one of them, like an API request per keystroke, wastes resources. Both patterns cut down the calls, but in different ways.

Debounce vs throttle at a glance

AspectDebounceThrottle
When it runsAfter events pause for the delayAt most once per interval
First eventDelayed until quietRuns immediately
Best forSearch, autosave, resize endScroll, drag, rapid clicks

Debounce: wait for a pause

Debounce starts a timer on each event and resets it whenever a new event arrives. The work only runs after the events stay quiet for the delay. This is the classic search-box pattern.

App.jsxApp.jsx
import { useEffect, useState } from "react";
function useDebouncedValue(value, delay) {
  const [debounced, setDebounced] = useState(value);
  useEffect(() => {
    const id = setTimeout(() => setDebounced(value), delay);
    return () => clearTimeout(id);
  }, [value, delay]);
  return debounced;
}

The Hook keeps a second value that only updates after the input has been stable for the delay. Each change clears the previous timer, so a fast typist never sends an intermediate request.

Throttle: cap the rate

Throttle runs the work immediately, then ignores further events until the interval passes. The first call happens right away, and later calls are spaced at a fixed rate.

App.jsxApp.jsx
import { useRef } from "react";
function useThrottledCallback(callback, wait) {
  const lastRun = useRef(0);
  return function throttled(...args) {
    const now = Date.now();
    if (now - lastRun.current < wait) return;
    lastRun.current = now;
    callback(...args);
  };
}

The throttled handler records when it last ran and skips calls inside the window. It stays responsive on the first event and steady after that, which suits continuous updates like a scroll position. If events keep coming, the handler still runs only once per window, so the total work stays bounded.

Which should you use

Use debounce when only the final result matters, like a search request after typing stops. A search box that fetches results should debounce the query, because only the last keystroke matters.

Use throttle when you need continuous updates at a steady rate, like a scroll listener that updates a progress bar. If the work only matters once the user pauses, debounce is the better fit. When in doubt, ask whether a late result is still useful.

What to learn next

Both patterns build on the event handling overview, and extracting the timer logic is the same technique covered in creating a custom Hook.

Rune AI

Rune AI

Key Insights

  • Debounce waits for a pause before running.
  • Throttle runs at most once per interval.
  • Debounce suits search and autosave.
  • Throttle suits scroll and drag updates.
  • Clear timers in cleanup to avoid leaks.
RunePowered by Rune AI

Frequently Asked Questions

When should I use debounce?

Use debounce when only the final result matters, like a search request that should run after the user stops typing.

When should I use throttle?

Use throttle when you need continuous updates at a steady rate, like a scroll position or drag feedback.

Do I need a library for this?

No. A small custom Hook with setTimeout and clearTimeout covers most cases, and the cleanup keeps timers from leaking.

Conclusion

Debounce delays work until rapid events pause, and throttle caps work to a steady rate. Pick debounce for final results and throttle for continuous updates.