Problems with debounce in useEffect

Every time your component re-renders, a new debounced verify function is created, which means that inside useEffect you are actually calling different functions which defeats the purpose of debouncing.

It’s like you were doing something like this:

const debounced1 = debounce(() => { console.log(state.username) }, 1000);
debounced1();

const debounced2 = debounce(() => { console.log(state.username) }, 1000);
debounced2();

const debounced3 = debounce(() => { console.log(state.username) }, 1000);
debounced3();

as opposed to what you really want:

const debounced = debounce(() => { console.log(state.username) }, 1000);
debounced();
debounced();
debounced();

One way to solve this is to use useCallback which will always return the same callback (when you pass in an empty array as a second argument). Also, I would pass the username to this function instead of accessing the state inside (otherwise you will be accessing a stale state):

import { useCallback } from "react";
const App => () {
  const [username, setUsername] = useState("");

  useEffect(() => {
    if (username !== "") {
      verify(username);
    }
  }, [username]);

  const verify = useCallback(
    debounce(name => {
      console.log(name);
    }, 200),
    []
  );

  return <input onChange={e => setUsername(e.target.value)} />;
}

Also you need to slightly update your debounce function since it’s not passing arguments correctly to the debounced function.

function debounce(func, wait, immediate) {
  var timeout;

  return (...args) => { <--- needs to use this `args` instead of the ones belonging to the enclosing scope
    var context = this;
...

demo

Note: You will see an ESLint warning about how useCallback expects an inline function, you can get around this by using useMemo knowing that useCallback(fn, deps) is equivalent to useMemo(() => fn, deps):

const verify = useMemo(
  () => debounce(name => {
    console.log(name);
  }, 200),
  []
);

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)