The problem
Who doesn't love a searchbox where you get instant suggestions? aka auto-complete, aka auto-suggestion, aka instant results?
In my years as a frontend engineer, I have designed my fair share of autocomplete search boxes; whether it be with jQuery, Angular or React and every single time, I found myself having to do some sort of debounce and for some reason, I always can't quite figure out whether to debounce the input's change handler or the subsequent fetch call...
So here we are - this is a post for future me to remind me how to do this properly in React.
1. Leave the input as an uncontrolled element
If you want to keep the value of the input box in a state, then handle it in the debounced onChange
handler but do not set the value
props of the input on that state property.
If the input box needs a value when it first mounts, then use defaultValue
props.
2. Create a memoized debounced version of your change handler
Do you normal thing and create an onChange
handler. So you would be doing your state change or data fetching in that handler.
Now wrap your pass the onChange
handler above into the debounce
utility from lodash
and wrap
Use the useMemo
hook to return the debounced onChange
handler.
const onChangeHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
// do some side effects here
}
const debouncedSearch = useMemo(() => {
return debounce(onChangeHandler, 500)
}, [])
// Use the debouncedSearch
<input name="search" placeholder="Search pokemons" onChange={debouncedSearch} />
3. Clean up the debounce on unmount
useEffect(() => {
return () => {
debouncedSearch.cancel()
}
})
Here is a codepen of a working example - https://codesandbox.io/embed/debounced-search-eit7yr?fontsize=14&hidenavigation=1&theme=dark