Created
November 18, 2023 09:24
-
-
Save mustafadalga/f148f987e5f6a8de1a332e49915cfda2 to your computer and use it in GitHub Desktop.
Unit Tests for useDeepCompareMemoize: Testing Deep Comparison React Hook with Vitest and Testing Library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { describe, it, expect } from "vitest"; | |
import { renderHook } from "@testing-library/react"; | |
import useDeepCompareMemoize from "./useDeepCompareMemoize"; | |
describe("useDeepCompareMemoize", () => { | |
it('should return a memoized version of the input value based on deep comparison', () => { | |
const initialData = { user: { name: 'John', age: 25, city: 'New York' } }; | |
const newData = { user: { name: 'Alice', age: 30, city: 'San Francisco' } }; | |
const identicalData = { user: { name: 'John', age: 25, city: 'New York' } }; | |
const { result, rerender } = renderHook( | |
({ data }) => useDeepCompareMemoize(data), | |
{ initialProps: { data: initialData } }, | |
); | |
expect(result.current).toEqual(initialData); | |
// Re-render with new data, expect result to change | |
rerender({ data: newData }); | |
expect(result.current).toEqual(newData); | |
// Re-render with identical data, expect result not to change | |
rerender({ data: identicalData }); | |
expect(result.current).toEqual(initialData); | |
}); | |
it('should handle primitive values', () => { | |
const initialNumber = 2023; | |
const newNumber = 2024; | |
const identicalNumber = 2023; | |
const { result, rerender } = renderHook( | |
({ data }) => useDeepCompareMemoize(data), | |
{ initialProps: { data: initialNumber } } | |
); | |
expect(result.current).toEqual(initialNumber); | |
// Re-render with the same value, expect result not to change | |
rerender({ data: newNumber }); | |
expect(result.current).toEqual(newNumber); | |
// Re-render with a new value, expect result to change | |
rerender({ data: identicalNumber }); | |
expect(result.current).toEqual(initialNumber); | |
}); | |
it('should handle arrays', () => { | |
const initialArray = [ 'apple', 'orange', 'banana' ]; | |
const newArray = [ 'grape', 'kiwi', 'pineapple' ]; | |
const identicalArray = [ 'apple', 'orange', 'banana' ]; | |
const { result, rerender } = renderHook( | |
({ data }) => useDeepCompareMemoize(data), | |
{ initialProps: { data: initialArray } } | |
); | |
expect(result.current).toEqual(initialArray); | |
// Re-render with a new array, expect result to change | |
rerender({ data: newArray }); | |
expect(result.current).toEqual(newArray); | |
// Re-render with an identical array, expect result not to change | |
rerender({ data: identicalArray }); | |
expect(result.current).toEqual(initialArray); | |
}); | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useRef } from 'react'; | |
import { isEqual, cloneDeep } from 'lodash'; | |
/** | |
* Custom React hook for deep comparison memoization. | |
* | |
* @remarks | |
* Traditional useMemo doesn't detect changes in nested data structures. | |
* This hook uses lodash's `isEqual` for deep comparison and returns a memoized version of the provided value. | |
* If the current value is different from the previous one (in a deep comparison sense), it clones and returns the new value. | |
* | |
* This hook can be particularly useful when combined with React's `useMemo` or `useCallback` to avoid unnecessary re-renders or recalculations when dealing with deep nested data structures. | |
* | |
* @param value - The value to be deeply compared and possibly memoized. | |
* @returns A memoized version of the input value based on deep comparison. | |
* | |
* @example | |
* ```tsx | |
* const data = { a: { b: { c: 1 } } }; | |
* | |
* const memoizedData = useDeepCompareMemoize(data); | |
* ``` | |
* | |
* @see {@link https://sft.hashnode.dev/solving-the-nested-object-change-detection-issue-with-usememo-in-react} for the original resource and explanation. | |
*/ | |
const useDeepCompareMemoize = <T>(value: T): T => { | |
const ref = useRef<T>(); | |
if (!isEqual(value, ref.current)) { | |
ref.current = cloneDeep(value); | |
} | |
return ref.current!; | |
}; | |
export default useDeepCompareMemoize; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment