React Curriculum

Machine Coding: useDebounce & useThrottle Custom Hooks

Medium100% Free~30 mins#react#machine-coding#custom-hooks#debounce#throttle#timers
Interview Answer (30-Second Summary)

useDebounce delays updating a value until after a specified delay has elapsed since the last change, canceling previous timers in useEffect cleanup. useThrottle ensures an action executes at most once per time window using useRef to track timestamps or trailing timers.

Key Learning Objectives
✓

Implement a production-grade useDebounce hook with cleanup cancellation.

✓

Implement a useThrottle hook that prevents rapid execution during scroll or resize events.

✓

Manage timers and cancel pending callbacks on component unmount.

✓

Explain when to debounce user input vs when to throttle high-frequency streams.

The Interview Problem & Context

Implement a reusable `useDebounce<T>(value: T, delay: number): T` hook that delays updating the returned value until `delay` milliseconds have elapsed without changes, and include full timer cleanup.

1import { useState, useEffect, useRef } from 'react';
2
3// 1. useDebounce Value Hook
4export function useDebounce<T>(value: T, delay: number): T {
5 const [debouncedValue, setDebouncedValue] = useState<T>(value);
6
7 useEffect(() => {
8 // Set timer to update state after delay
9 const timer = setTimeout(() => {
10 setDebouncedValue(value);
11 }, delay);
12
13 // Cancel timer if value or delay changes before timeout fires
14 return () => {
15 clearTimeout(timer);
16 };
17 }, [value, delay]);
18
19 return debouncedValue;
20}
21
22// 2. useThrottle Hook (Leading + Trailing execution)
23export function useThrottle<T>(value: T, interval = 500): T {
24 const [throttledValue, setThrottledValue] = useState<T>(value);
25 const lastExecuted = useRef<number>(Date.now());
26
27 useEffect(() => {
28 const now = Date.now();
29 const elapsed = now - lastExecuted.current;
30
31 if (elapsed >= interval) {
32 lastExecuted.current = now;
33 setThrottledValue(value);
34 } else {
35 const timer = setTimeout(() => {
36 lastExecuted.current = Date.now();
37 setThrottledValue(value);
38 }, interval - elapsed);
39
40 return () => clearTimeout(timer);
41 }
42 }, [value, interval]);
43
44 return throttledValue;
45}
Deep Architectural Explanation

Debounce vs Throttle: When to Use Which

1. Debouncing (Wait for quiet period):

  • Concept: Postpones execution until N milliseconds have passed since the LAST event.
  • Use Cases:
    • Search auto-complete typeahead (do not fire HTTP request on every keystroke).
    • Auto-saving draft forms (wait until user stops typing for 1 second).
    • Window resize recalculations (wait until resize drag completes).

2. Throttling (Rate-limiting frequency):

  • Concept: Guarantees execution at a regular maximum rate (e.g. at most once every 200ms).
  • Use Cases:
    • Infinite scroll scroll position tracking.
    • Drag-and-drop mouse movement coordinates.
    • Rate-limiting button clicks on submit actions.

Mechanics of useDebounce:

  1. When value changes, useEffect schedules setTimeout.
  2. If value changes again before delay milliseconds pass, React executes the effect cleanup function, running clearTimeout(timer).
  3. The previous pending timer is aborted; a new timer begins.
  4. Only when the user pauses typing does the timer expire, updating debouncedValue and triggering a single re-render.
Common Interview Traps & Pitfalls
✕

Forgetting the cleanup function in useEffect, leading to multiple queued timers firing out of order.

✕

Re-creating the debounce delay function inside render without useCallback.

✕

Using debounce when throttle is needed (e.g. infinite scroll where user never stops scrolling).

Senior Interviewer Follow-Up Probes
?

How would you implement useDebouncedCallback for imperative functions (like an analytics logger)?

?

How do you test useDebounce in Jest using `jest.useFakeTimers()` and `jest.advanceTimersByTime()`?

?

What are the memory implications of storing large object values in useDebounce?

Frequently Asked Interview Questions
What is the difference between debounce and throttle?

Debounce delays execution until a pause of N milliseconds occurs. Throttle limits execution to a fixed frequency of at most once every N milliseconds regardless of activity.

Because debouncedValue state is initialized with the initial value argument, ensuring the component displays valid data without delay on first render.

The useEffect cleanup function returns () => clearTimeout(timer), which React calls automatically whenever dependencies change or when the component unmounts.

Yes, using a useDebouncedCallback hook that wraps a function in a ref and returns a debounced invoker.

Use renderHook from @testing-library/react with jest.useFakeTimers(). Change props with rerender and advance timers with act(() => jest.advanceTimersByTime(500)).

No, it reduces re-renders significantly because internal state updates only fire once after the quiet period rather than on every keystroke.