useEffect.dev
← Back to lessons

Lesson 9. Debouncing a user input 2. Debouncing the input with another state

The idea will be to have another state debouncedSearch, which will be updated 300 milliseconds after search. To do this, when search is updated, we will call setTimeout to update debouncedSearch.

Note that there are a lot of ways to implement debouncing, each with its small differences. The one we’ll see here is the easiest one to understand and implement:

  • If we set search to “A”, we start a timeout of 300 milliseconds, after which we update debouncedSearch to “A”.
  • If before the first timeout ends, search is updated to “AB”, we cancel the first timeout, then start a new one of 300 ms, at the end of which we update debouncedSearch to “AB”.
const [debouncedSearch, setDebouncedSearch] = useState(search)
useEffect(() => {
let timeout = setTimeout(() => {
setDebouncedSearch(search)
}, 300)
return () => clearTimeout(timeout)
}, [search])

With this variant, debouncedSearch will always be updated 300 milliseconds after the last character is typed.

Another way to do would be, at the end of the timeout, to get the current value of search (using a ref, see lesson 6). But let’s stay in the easy way here and solve our problem with as few complexity as possible.

Here is the full code of our component using debouncing:

Result

Now the state search contains the value entered in the input, and debouncedSearch the same value but updated 300 milliseconds later. This is this last value that we want to use in the useEffect responsible for calling the API and performing the search.

This debouncing behavior is very common, and you may need it in several places in your application(s), so maybe it is a good idea to extract it into a custom hook. What do you think?