All questions

useThrottle

Premium

useThrottle

Build a React hook that returns a throttled copy of a value. As the source value changes — on every keystroke, scroll event, or window resize — the throttled copy updates at most once per interval milliseconds, so anything reading it (an expensive search, a chart redraw) runs on a steady cadence instead of on every change. Throttle is the close cousin of debounce, but they answer different questions: debounce waits for the source to go quiet before committing, while throttle commits on a fixed clock no matter how busy the source is. The catch most people miss: the very last value of a burst must still land, even though it arrived before the interval elapsed.

Signature

function useThrottle<T>(value: T, interval: number): T;

The hook returns the throttled value. The first render returns value as-is.

Examples

function Search({ query }) {
  // `query` may change on every keystroke; `throttled` changes at most
  // once every 200ms, so we only re-run the expensive search on a cadence.
  const throttled = useThrottle(query, 200);
  const results = useMemo(() => expensiveSearch(throttled), [throttled]);
  return <ResultList items={results} />;
}
// interval = 200, source changes at t = 0, 50, 90, 130 with values a,b,c,d
// t=0:   throttled === 'a'   (first value lands immediately)
// t=50:  throttled === 'a'   (inside the interval — held)
// t=90:  throttled === 'a'   (still inside — held)
// t=130: throttled === 'a'   (still inside — held)
// t=200: throttled === 'd'   (interval elapsed — the LATEST value lands)

Notes

  • First value is immediate. On the initial render, the throttled value equals the source value. There's no wait before the first read.
  • At most one update per interval. A burst of changes inside one window must not commit one update per change — only the latest, once the window closes.
  • The last value must not be dropped. This is the trailing edge. If the final change of a burst arrives before the interval elapses, it still has to land within roughly one interval — never lost.
  • Throttle is not debounce. Debounce resets its timer on every change and fires only after the source is quiet. Throttle keeps a fixed cadence and fires regardless. Don't conflate them.
  • Clean up on unmount. Any pending trailing timer must be cleared when the component unmounts — no state updates into a dead component.

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