Implement the useDebounce custom hook in React



This content originally appeared on DEV Community and was authored by Debajit Mallick

Introduction

In modern web apps, debouncing is a powerful feature—especially when dealing with frequent user input, such as search bars, form validation, or filtering data.

If you’re preparing for React interviews, one common question you’ll face is:

“How do you implement a useDebounce hook in React?”

In this blog, we’ll build a useDebounce custom hook from scratch, explore why it’s useful, and show how you can integrate it into real-world projects.

What is Debouncing?

Debouncing ensures that a function is only executed after a certain delay and only if no new event has occurred in the meantime.

It’s especially useful for:

  • Search input fields
  • API calls during typing

The useDebounce Hook

Let’s dive right into the code:

import { useEffect, useState } from 'react';

const useDebounce = (value, delay) => {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    let timerId = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

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

  return debouncedValue;
};

export default useDebounce;

Now, let’s understand the code step by step:

1. Local State

const [debouncedValue, setDebouncedValue] = useState(value);

We store a version of the value that will only be updated after the delay has passed.

2. Effect Hook

useEffect(() => {
  let timerId = setTimeout(() => {
    setDebouncedValue(value);
  }, delay);

  return () => {
    clearTimeout(timerId);
  };
}, [value, delay]);
  • Every time the value or delay changes, we start a new timer.
  • If a new change comes in before the delay ends, we clear the previous timer—this is the key to debouncing!
  • Only after the user stops typing (or stops triggering changes) for the full delay, we update the debouncedValue.

3. Returning the Debounced Output

return debouncedValue;

This allows the component to use the stable, debounced value. It is great for delaying expensive operations like API calls.

Example Usage

Let’s see how we can use this hook in a search input component:

import React, { useState, useEffect } from 'react';
import useDebounce from './useDebounce';

const SearchBox = () => {
  const [query, setQuery] = useState('');
  const debouncedQuery = useDebounce(query, 500);

  useEffect(() => {
    if (debouncedQuery) {
      // Simulate API call
      console.log('Searching for:', debouncedQuery);
    }
  }, [debouncedQuery]);

  return (
    <input
      type="text"
      placeholder="Search users..."
      value={query}
      onChange={(e) => setQuery(e.target.value)}
    />
  );
};

export default SearchBox;
  • The log message only appears 500ms after the user stops typing.
  • Prevents unnecessary API calls during rapid keystrokes.

Conclusion

The useDebounce custom hook is an elegant solution to a common problem, and it’s a great way to showcase your React skills in interviews and in production code. Whether you’re optimizing a search bar or building a responsive UI, debouncing will make your app feel smoother and more efficient. If you liked this blog and want to learn more about Frontend Development and Software Engineering, you can follow me on Dev.


This content originally appeared on DEV Community and was authored by Debajit Mallick