DEV Community

Przemek Wolnik
Przemek Wolnik

Posted on

How to execute a function only after the user stops typing?

I was implementing simple search functionality. I've added input field with onChange handler. But I wanted to perform actual search method some time after the user stops typing.

Looks like a perfect place to use debounce here, right?

I thought that I would just put debounced search function inside useEffect hook. I also had to make sure that debounced search function will stay the same between renders.

After playing for a while with useCallback hook (replaced later by useRef hook which is more appropriate for this job) I had a working solution.


But on second though it turned out the simplest solution is to use good old friend setTimeout combined with clearTimeout.

So here it is:

import React, { useState, useEffect } from 'react';

export const App = () => {
  const [value, setValue] = useState("");

  const handleOnChange = (event) => {

  useEffect(() => {
    const timeoutId = setTimeout(() => console.log(`I can see you're not typing. I can use "${value}" now!`), 1000);
    return () => clearTimeout(timeoutId);
  }, [value]);

      <input onChange={handleOnChange} value={value} />

PS I found a similar (the same?) solution with the journey explained in more details here: Enjoy!

Top comments (6)

wbialekmerixstudio profile image

In this solution useEffect will trigger after the first render, so we will see text in the console without any typing. If we want to fetch some data "onChange" then we will have an extra redundant request.
Maybe a better solution will be to move setTimeout to handleOnChange function?

przemwo profile image
Przemek Wolnik

Thank you for the comment! I a gree with the "trigger after the first render" issue.
However if we move setTimeout to handleOnChange we will have to take care of handling clear timeout manually (useEffect do it for us with the return callback fn).

The other thing is that logging to the console / fetching some data etc. are side effects to value changes - useEffect seems like a perfect choice here.

I would rather add some extra logic inside useEffect (e.g. using useRef) to make sure that our effect runs only after the second and every subsequent render. What do you think?

hnakao profile image

Hi, here... maybe you want to take a look to this hook:

akhilalekha profile image

Thanks for this!!

6km profile image
Mohammed Taha

Thanks, this helped me a lot!

shamxeed profile image
Musa Danjuma

Thanks a lot this has helped me!!!