Skip to content

Instantly share code, notes, and snippets.

@felipecsl
Created September 8, 2022 14:49
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save felipecsl/afb987f8b6059814cff0a2ca6020e108 to your computer and use it in GitHub Desktop.
Save felipecsl/afb987f8b6059814cff0a2ca6020e108 to your computer and use it in GitHub Desktop.
Debounced React useEffect with a wait time in milliseconds
// https://stackoverflow.com/a/67504622/51500
import {
DependencyList,
EffectCallback,
useCallback,
useEffect,
useRef,
} from "react";
import { debounce } from "lodash";
export function useLazyEffect(
effect: EffectCallback,
deps: DependencyList = [],
wait = 300
) {
const cleanUp = useRef<void | (() => void)>();
const effectRef = useRef<EffectCallback>();
effectRef.current = useCallback(effect, deps);
const lazyEffect = useCallback(
debounce(() => (cleanUp.current = effectRef.current?.()), wait),
[]
);
useEffect(lazyEffect, deps);
useEffect(() => {
return () =>
cleanUp.current instanceof Function ? cleanUp.current() : undefined;
}, []);
}
@LightSean
Copy link

Nice! one thing - the original useEffect is cleaning up on every new invocation. (happens if the dependency array is not empty, and a value changes)
i suggest replacing those lines:

const lazyEffect = useCallback(
    debounce(() => (cleanUp.current = effectRef.current?.()), wait),
    []
  );

With those:

const lazyEffect = useCallback(
    debounce(() => {
      if(cleanUp.current instanceof Function) {
        cleanUp.current();
      }
      cleanUp.current = effectRef.current?.()
    }, wait),
    []
  );

@btbenedi
Copy link

thank you for this, it saved my bacon today with a tricky debounce setup I was working on

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment