React - Frontend - Web Development

Build and Use a Custom Debounce Hook in React

Learn how to create a reusable useDebouncedValue hook in React to delay state updates until user input stabilizes, helping reduce unnecessary renders and API calls.

Illustration of React hooks concept with debounce icon overlay

How to Build and Use a Custom Debounce Hook in React

When working with React apps, we often deal with events that fire rapidly - like typing in an input, resizing a window, or dragging elements around. Triggering logic on every single event can result in unnecessary re-renders or wasted API calls.

This is where debouncing comes in. Debouncing ensures that a function or state update only runs after a certain delay has passed since the last trigger. In this article, we’ll build a reusable useDebouncedValue hook in React and see how to apply it effectively.

Why Debouncing Matters

Imagine a search bar that makes an API call on every keystroke. Typing “react” would fire five API requests ('r', 're', 'rea', 'reac', 'react') - unnecessary and inefficient. With debouncing, the search request only fires once the user stops typing for a short period (e.g., 300ms).

Creating the useDebouncedValue Hook

Here’s the full implementation:

useDebounce.tsx
import { useEffect, useState } from "react";

export function useDebouncedValue<T>(value: T, delay: number = 300) {
  const [debounced, setDebounced] = useState<T | undefined>(undefined);

  useEffect(() => {
    const id = setTimeout(() => {
      setDebounced(value);
    }, delay);

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

  return debounced;
}

How It Works

  • useState - Stores the debounced value.
  • useEffect - Sets a timeout every time value changes.
  • Timeout reset - If a new change happens before the delay finishes, the previous timeout is cleared.
  • Result - The debounced value only updates once the input “settles.”