useDebounce hook

A small generic hook for debouncing a fast-changing value — search inputs, resize handlers, anything you don't want firing on every keystroke.

1 min read

Sabin Shrestha

Full-Stack Developer — Next.js, React & React Native

The one hook I copy into nearly every project. Debounces a value so downstream effects (a search request, a save-to-localStorage call) only fire once the value has settled.

hooks/useDebounce.ts
import { useEffect, useState } from "react";
 
export function useDebounce<T>(value: T, delayMs = 300): T {
  const [debounced, setDebounced] = useState(value);
 
  useEffect(() => {
    const timeout = setTimeout(() => setDebounced(value), delayMs);
    return () => clearTimeout(timeout);
  }, [value, delayMs]);
 
  return debounced;
}

Usage #

SearchInput.tsx
function SearchInput() {
  const [query, setQuery] = useState("");
  const debouncedQuery = useDebounce(query, 300);
 
  useEffect(() => {
    if (debouncedQuery) runSearch(debouncedQuery);
  }, [debouncedQuery]);
 
  return <input value={query} onChange={(e) => setQuery(e.target.value)} />;
}
Note

The cleanup function matters here — without clearTimeout on unmount/re-run, a stale timeout from a previous keystroke can still fire and overwrite a newer value.

© 2026 Sabin Shrestha