Search code examples
javascripthtmlreactjsdebouncing

Debounce in ReactJS


I am trying to implement debounce in my search input in React. The below code is causing the delay but its firing the same number of times.

Example - If I type abcd in less than 2 seconds(delay) my debounced value should be abcd instead I am getting console with all values-

Debounced: a 
Debounced: ab 
Debounced: abc 
Debounced: abcd 

What I am assuming, if I type abcd then it should make a single call instead of 4 in this case.

Code -

import { useState } from 'react';

function debounce(cb, delay) {
  let timeoutId;
  return function (...args) {
    if (timeoutId) {
      clearTimeout(timeoutId);
    }

    timeoutId = setTimeout(() => {
      cb(...args);
    }, delay);
  };
}

export default function App() {
  const [searchVal, setSearchVal] = useState('');
  const [debounceVal, setDebounceVal] = useState('');

  const debouncedChange = debounce((inputValue) => {
    console.log('Debounced:', inputValue);
    setDebounceVal(inputValue);
  }, 2000);

  const handleChange = (e) => {
    const inputValue = e.target.value;
    setSearchVal(inputValue);
    debouncedChange(inputValue);
  };

  return (
    <div className="App">
      <h1>Debounce</h1>

      <div className="container">
        <div className="search-input">
          <input type="text" value={searchVal} onChange={handleChange} />
        </div>

        <div className="search-data">{debounceVal}</div>
      </div>
    </div>
  );
}

Let me know if I am doing something wrong here with the code or my understanding around debounce.


Solution

  • I would recommend using useEffect hook to listen to any changes and do a clean-up as well. Here's a working DEMO

    function useDebounce(cb, delay) {
      const [debounceValue, setDebounceValue] = useState(cb);
      useEffect(() => {
        const handler = setTimeout(() => {
          setDebounceValue(cb);
        }, delay);
    
        return () => {
          clearTimeout(handler);
        };
      }, [cb, delay]);
      return debounceValue;
    }