Don't fetch on every keystroke. Debounce the input.
Without debouncing: User types "react" → API calls.
With debouncing: Wait ms after last keystroke → API call.
Implementation:
const debouncedFetch = useMemo(
() => debounce(query => {
fetchSuggestions(query).then(setSuggestions);
}, 300),
[]
);
useEffect(() => {
if (query.length >= minChars) {
debouncedFetch(query);
}
}, [query]);
Typical values: -ms debounce. Minimum - characters before searching.