You need to enable JavaScript to run this app.

useDeepEffect

An enhanced version of the useEffect hook with deep comparison on the dependencies.

Source

import { useEffect, useRef, useMemo } from "react";
import deepEqual from "fast-deep-equal/react";

interface DeepEffectHook {
  (...args: Parameters<typeof useEffect>): ReturnType<typeof useEffect>;
}

/**
 * react `useEffect` hook with fast and deep comparison on its dependencies.
 *
 * ⚠️ Usage with **no** dependencies or **primitive** ones is not allowed
 */
const useDeepEffect: DeepEffectHook = function useDeepEffect(
  callback,
  dependencies
) {
  const ref = useRef(dependencies);
  const signalRef = useRef(0);

  if (!deepEqual(dependencies, ref.current)) {
    ref.current = dependencies;
    signalRef.current += 1;
  }

  // eslint-disable-next-line react-hooks/exhaustive-deps
  const deps = useMemo(() => ref.current, [signalRef.current]);

  // eslint-disable-next-line react-hooks/exhaustive-deps
  return useEffect(callback, deps);
};

Example

const [state, setState] = useState<{ a?: unknown; b?: unknown }>({
  a: null,
  b: null,
});

useDeepEffect(() => {
  // do stuff
}, [state]);

Test

import { renderHook } from "@testing-library/react";
import useDeepEffect from "@hooks/useDeepEffect";

test("useDeepEffect should handle changing values as expected", () => {
  const callback = jest.fn();
  let deps = [{ a: "b" }];

  const { rerender } = renderHook(() => useDeepEffect(callback, deps));

  expect(callback).toHaveBeenCalledTimes(1);

  deps = [{ a: "b" }];

  rerender();
  expect(callback).toHaveBeenCalledTimes(1);

  deps = [{ a: "c" }];

  rerender();
  expect(callback).toHaveBeenCalledTimes(2);
});
Favourite Books
BooksPoems
Favourite Songs
PlaylistsArtists
Favourite Shows
AnimationsSeriesAnime