tech

useDebounceUpdate - Running an effect after a timeout

Execute a function after a timeout every time your data changes. Reset the timer if the data changes again during the timeout.


Sandro Maglione

Sandro Maglione

Software

Execute a function after a timeout every time your data changes. Reset the timer if the data changes again during the timeout.

Sometimes when the user updates some state, we want to make an API request to sync the state remotely. We cannot run a function every time the user changes the data however.

What we do instead is debounce the state update, i.e. waiting a fixed amount of time after the user stops interacting before making the request. Furthermore, we want to reset the timeout if in the meantime the user changes the state again.

Well, that's what useDebounceUpdate is made for!

isFirstRender is used to avoid running execute at first render (which is probably something that you don't want here 💁🏼‍♂️).

Every time data changes timer resets and the execute function will be called again only after timeout milliseconds.

useDebounceUpdate.ts
import { useEffect, useRef } from "react";

/**
 * Run the `execute` function after `timeout` milliseconds.
 * If the value of `data` changes, reset the timer.
 */
export const useDebounceUpdate = <Data>({
  execute,
  data,
  timeout = 2000,
}: {
  data: Data;
  timeout?: number;
  execute: (value: Data) => void;
}): void => {
  const isFirstRender = useRef(true);
  const timer = useRef<ReturnType<typeof setTimeout>>();
  useEffect(() => {
    if (!isFirstRender.current) {
      if (timer.current) {
        clearTimeout(timer.current);
      }

      timer.current = setTimeout(() => {
        execute(data);
      }, timeout);
    } else {
      isFirstRender.current = false;
    }
  }, [data]);
};

👋・Interested in learning more, every week?

Every week I dive headfirst into a topic, uncovering every hidden nook and shadow, to deliver you the most interesting insights

Not convinced? Well, let me tell you more about it