Debounced search input with useEffect and useRef
FormsdebouncesearchuseEffectuseRefforms
A reusable search input that delays API calls until user stops typing for a specified duration.
TSX
import { useState, useEffect, useRef } from 'react';
export function DebouncedSearchInput({
onSearch,
delay = 300,
}: {
onSearch: (query: string) => void;
delay?: number;
}) {
const [query, setQuery] = useState('');
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
if (query.trim() !== '') {
timeoutRef.current = setTimeout(() => {
onSearch(query);
}, delay);
}
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, [query, delay, onSearch]);
return (
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
aria-label="Search input"
/>
);
}This component accepts a onSearch callback and optional delay (in ms) to trigger search only after typing pauses. It uses useRef to persist the timeout ID across renders and useEffect to reset/clear it on every query change. Important: always clean up the timeout in the effect’s cleanup function to avoid memory leaks or stale callbacks. Usage: <DebouncedSearchInput onSearch={(q) => fetchResults(q)} delay={500} />. Note that onSearch is called with the current query, including empty strings — add if (query.trim()) inside onSearch if you want to skip empty queries.