useDebounce
Debounce any changing value in React to improve performance and control effects.
useDebounce
A reusable React hook to debounce any value. It delays updating the returned value until after the specified delay period has passed without changes. Useful for optimizing performance in high-frequency state updates like search input or resize events.
📦 Installation
This hook is framework-independent and works in React and Next.js projects.
🧠 Purpose
useDebounce
helps prevent frequent re-renders or side-effects by only acting on the final value after a specified period of inactivity.
💡 Use Cases
- Delay search queries while typing
- Reduce API calls on input changes
- Debounce expensive calculations
- Handle scroll/resize events efficiently
📁 Hook Code
import { useState, useEffect } from "react";
export function useDebounce<T>(value: T, delay: number = 500): T {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debounced;
}
import { useState, useEffect } from "react";
export function useDebounce(value, delay = 500) {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debounced;
}
🧪 Example
import { useState, useEffect } from "react";
import { useDebounce } from "@/hooks/useDebounce";
export default function SearchBar() {
const [query, setQuery] = useState("");
const debouncedQuery = useDebounce(query, 500);
useEffect(() => {
if (debouncedQuery) {
console.log("Triggering API call with:", debouncedQuery);
// callSearchAPI(debouncedQuery);
}
}, [debouncedQuery]);
return (
<input
type="text"
placeholder="Search here..."
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
);
}
import { useState, useEffect } from "react";
import { useDebounce } from "@/hooks/useDebounce";
function SearchBar() {
const [query, setQuery] = useState("");
const debouncedQuery = useDebounce(query, 500);
useEffect(() => {
if (debouncedQuery) {
console.log("Triggering API call with:", debouncedQuery);
// callSearchAPI(debouncedQuery);
}
}, [debouncedQuery]);
return (
<input
type="text"
placeholder="Search here..."
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
);
}
🧩 Hook Signature
function useDebounce<T>(value: T, delay: number): T;
📝 Parameters
Prop | Type | Default |
---|---|---|
delay? | number | 500 |
value | T | - |
🎯 Returns
Prop | Type | Default |
---|---|---|
debouncedValue | T | - |
🧪 Testing Tip
Log both query
and debouncedQuery
to clearly see the difference during typing:
console.log({ query, debouncedQuery });
🧯 Visual Timeline
Debounce Flow Explanation
When the user types quickly, the debounce timer resets. Only after the user stops typing for the specified delay does the debounced value update.
User types: h he hel hell hello Time passed: -- 100 200 300 400ms ← {" "}
debounce timer resets
Debounced value: hello (after 500ms pause)
🏁 Summary
- ✅ Clean, reusable hook
- ✅ Works in both JS and TS
- ✅ Ideal for search, resize, or scroll performance
- ✅ Simple to use and extend
🙋 Contribution
Found a bug or improvement? Submit a PR on GitHub