DEVOLOGIST</>

React Hooks

How to Create a useDebounce Hook in React & Next.js

Optimizing search inputs and heavy operations is crucial for web performance. In this guide, we will build a professional useDebounce custom hook.

The Problem

When a user types in a search bar, an input event fires on every single keystroke. If you trigger an API request on every event, you will spam your server with unnecessary requests.

The Solution: Debouncing

Debouncing ensures that a function only runs after a certain period of inactivity. This means the API call will only trigger after the user has stopped typing for a set amount of time.

Step 1: Implement the Hook

Create the following custom hook to manage the delayed value:

import { useEffect, useState } from "react";
/**
* A custom hook that returns a debounced version of the provided value.
* @param {any} value - The value to debounce.
* @param {number} delay - The delay in milliseconds.
*/
export function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(value);
}, delay);
// Cleanup the timer if the value changes before the delay is reached
return () => {
clearTimeout(timer);
};
}, [value, delay]);
return debouncedValue;
}

Step 2: Using the Hook in a Component

Now, let's see how to use this hook in a real-world scenario, such as a search input:

'use client'
import { useDebounce } from "@hooks/useDebounce";
import React, { useState } from "react";
const SearchComponent = () => {
const [value, setValue] = useState("");
// This value will only update after 500ms of no typing
const debouncedSearch = useDebounce(value, 500);
return (
<div className="container mx-auto flex flex-col gap-2 mt-10 p-4 border rounded-lg">
<label className="font-bold">Search Input:</label>
<input
className="border p-2 rounded"
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="Type to search..."
/>
<div className="mt-4 space-y-2">
<div className="flex items-center gap-2">
<span className="text-gray-500">Raw Value: </span>
<span className="font-mono">{value}</span>
</div >
<div className="flex items-center gap-2">
<span className="text-blue-600 font-semibold">Debounced Value: </span>
<span className="font-mono font-bold">{debouncedSearch}</span>
</div >
</div>
</div>
);
};
export default SearchComponent;

Summary

  • Performance: Reduces the number of unnecessary function calls/API requests.
  • Efficiency: Great for search bars, window resizing, and auto-save features.
  • Clean Code: Decouples the input state from the expensive logic.