Joonas' Note

Joonas' Note

[React] useDeepMemo 본문

개발/Javascript

[React] useDeepMemo

2025. 4. 15. 00:22 joonas

    primitive 하게 비교되지 않는 object들은 의존성 배열에서 같은 값으로 인식하지 않는다.
    이건 javascript 의 비교 연산자가 얕은 비교를 하기 때문이다. 아래는 대표적인 사례.

    {} == {}
    // output: false

    즉, 아래의 memo는 전혀 캐싱되지 않기 때문에 어떤 스노우볼을 굴릴 지 모른다.

    const complexObject = {a:1, b:2, c:"xyz"}
    // 의존성 배열은 항상 다른 값으로 인식된다.
    const complexMemo = useMemo(() => complexObject, [complextObject])

    아래와 같이 비교 대상을 문자열로 변경해서 해결하는 방법도 있는데, 보기에도 느껴지지만 그렇게 권장되는 방법은 아니다.

    const complexObject = {a:1, b:2, c:"xyz"}
    const complexMemo = useMemo(() => complexObject, [JSON.stringify(complextObject)])

    위 방법과 크게 다르지 않지만, 핵심은 의존성 배열 내의 객체를 비교해야 하는 것이므로, 구조적으로 변경할 수 있게 아래처럼 작성해서 사용하고 있다.

    // useDeepHooks.ts
    import { useRef, useEffect, useMemo } from 'react'
    
    const serialize = (obj: any) => {
      if (typeof obj === 'object') {
        return JSON.stringify(obj)
      }
      return obj
    }
    
    export function useDeepMemo(callback: () => any, dependencies: any[]) {
      const depsStringified = useMemo(
        () => dependencies.map(serialize),
        dependencies,
      )
      return useMemo(() => callback(), depsStringified)
    }

    리액트 개발자 중 한 명은 이 외에도 2가지 방법을 더 제시하고 있다.

    그 외에도 ref 를 사용해서 상태를 들고 있는 방법도 있는데, Object 비교에서 실수한건지 제대로 동작하진 않았다.

    참고

     

    When to useMemo and useCallback

    Stay up to date Stay up to date All rights reserved © Kent C. Dodds 2025

    kentcdodds.com

     

    useCallback/useEffect support custom comparator · Issue #14476 · facebook/react

    Currently we can pass an array as second argument when using useCallback or useEffect like below: useCallback(()=> { doSth(a, b) }, [a, b]) // how to do deep equal if a is an object ? The problem i...

    github.com

     

    Comments