reactjsdebouncing

How to use debounce hooks in React


import { useEffect, useState } from 'react';

export default function useDebounce(text: string, delay: number) {
  const [value, setValue] = useState('');

  useEffect(() => {
    const timerId = setTimeout(() => {
      setValue(text);
    }, delay);
    return () => {
      clearTimeout(timerId);
    };
  }, [text, delay]);
  return value;
}


I used to make and use useDebounce hook. However, using useDebounce in resize event has some problems. The useDebounce hook must run at the top of the component because it uses useEffect inside. However, the resize function is set to run on useEffect as shown below.

Also, the above code takes value as a factor, but I think we need to receive it as callback to use the below code.

  useEffect(() => {
    const handler = () => {
      if (liRef.current) setWidth(liRef.current.clientWidth);
    };

    window.addEventListener('resize', handler);
    return () => window.removeEventListener('resize', handler);
  }, []);

How do I use the above code to utilize the existing useDebounce?


Solution

  • I think rather than implementing debounce through useEffect, it would be better to implement the debounce logic as a function.

    UseEffect is executed when the states referenced by deps change. In other words, since it is a logic that can be missed if you only follow the execution flow, it is difficult to figure out which flow this useEffect was derived from when performing maintenance later, and it can be difficult to debug.

    Example

    Custom Debounce

    function debounce(func, timeout = 300) {
      let timer;
      return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => {
          func.apply(this, args);
        }, timeout);
      };
    }
    
    function saveInput() {
      console.log('Saving data');
    }
    const processChange = debounce(() => saveInput());
    
    <input type="text" onkeyup="processChange()" />
    

    And if you use lodash, you can just import to use it.

    Lodash Debounce

    import { debounce } from 'lodash';
    
    const debounceOnChange = debounce(() => {
      console.log("This is a debounce function");
    }, 500);
    

    Hope this helps :)