GadgetForge

GadgetForge

The Difference Between Debounce and Throttle and How to Use Them


In web applications, debounce and throttle are commonly used to prevent events from firing too frequently.

Although they may seem similar at first glance, they work differently and serve different purposes.

This article covers their definitions, key differences, typical use cases, and how to implement and use them in React.


Debounce vs Throttle – Key Differences

AspectDebounceThrottle
BehaviorWaits for a quiet period after the last event, then executes onceExecutes at most once every fixed time interval
Main PurposePrevent excessive calls from rapid successive eventsLimit the rate of frequently occurring events
Typical Use CasesSearch autocomplete, preventing duplicate button clicksScroll events, window resize events

What is Debounce?

Debounce is a technique that ensures a function is only executed after a certain amount of time has passed without any new events being triggered. It is especially useful when users can trigger many events in a short time (typing, rapid clicking, etc.).

Common Debounce Use Cases:

  • Search autocomplete: Instead of sending an API request on every keystroke, wait until the user stops typing for a short period.
  • Prevent double-click / spam clicks: Ignore rapid successive clicks on the same button.

What is Throttle?

Throttle ensures that a function is executed at most once every specified time interval, no matter how many times the event is triggered during that period. It is ideal for performance optimization with high-frequency events.

Common Throttle Use Cases:

  • Scroll event handling: Update UI or fetch data only every few hundred milliseconds while scrolling.
  • Window resize events: Avoid recalculating layout or running expensive operations on every pixel change.

Code Implementation

This article uses React hook-style implementations (useDebounce and useThrottle) rather than plain utility functions.

utils.tsts
import { useState, useEffect, useRef } from "react";

// Debounce Hook
export const useDebounce = <T,>(value: T, delay: number = 500): T => {
  const [debouncedValue, setDebouncedValue] = useState<T>(value);

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedValue(value), delay);
    return () => clearTimeout(timer);
  }, [value, delay]);

  return debouncedValue;
};

// Throttle Hook
export const useThrottle = <T,>(value: T, delay: number = 500): T => {
  const [throttledValue, setThrottledValue] = useState<T>(value);
  const lastRan = useRef<number>(Date.now());

  useEffect(() => {
    const handler = setTimeout(() => {
      if (Date.now() - lastRan.current >= delay) {
        setThrottledValue(value);
        lastRan.current = Date.now();
      }
    }, delay - (Date.now() - lastRan.current));

    return () => clearTimeout(handler);
  }, [value, delay]);

  return throttledValue;
};

Debounce Example (Search Input)

 javascript
import { useState, useEffect, ChangeEvent } from "react";
import { useDebounce } from "./utils";

export default function SimpleDebounceExample() {
  const [inputValue, setInputValue] = useState<string>("");
  const debouncedValue = useDebounce<string>(inputValue, 500);

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    setInputValue(e.target.value);
  };

  useEffect(() => {
    console.log(`Debounced Value: ${debouncedValue}`);
    // Here you would usually trigger API call or heavy computation
  }, [debouncedValue]);

  return (
    <div style={{ padding: "20px" }}>
      <h1>Simple Debounce Example</h1>

      <div style={{ marginBottom: "20px" }}>
        <label htmlFor="search">Text input:</label>
        <input
          id="search"
          type="text"
          value={inputValue}
          onChange={handleChange}
          placeholder="Type something..."
        />
      </div>

      <div>
        <p>Debounced Value: {debouncedValue}</p>
      </div>
    </div>
  );
}

Throttle Example (Scroll Position)

 javascript
import { useState, useEffect } from "react";
import { useThrottle } from "./utils";

export default function ScrollThrottleExample() {
  const [scrollPosition, setScrollPosition] = useState < number > 0;

  const throttledScrollPosition = useThrottle < number > (scrollPosition, 1000);

  useEffect(() => {
    const handleScroll = () => {
      setScrollPosition(window.scrollY);
    };

    window.addEventListener("scroll", handleScroll);
    return () => window.removeEventListener("scroll", handleScroll);
  }, []);

  return (
    <div style={{ height: "200vh", padding: "20px" }}>
      <h1>Scroll Event with Throttle Example</h1>
      <p>Current scroll position: {throttledScrollPosition}px</p>
    </div>
  );
}

Plain Functions (throttleHelper) vs React Hooks (useThrottle) – Comparison

AspectPlain function (throttleHelper / debounceHelper)React Hook (useThrottle / useDebounce)
Usage environmentCan be used anywhere (React or non-React)Only inside React components
Code complexitySimple and conciseSlightly more complex (hooks + state)
State integrationHarder to connect with React stateNaturally integrates with React state
Lifecycle controlNo built-in lifecycle managementControlled via useEffect cleanup
MemoizationMust handle memoization manuallyEasy to optimize with useCallback, useRef, etc.
ReusabilityFramework-agnosticReact-specific


Related Posts in Series
Collapse