7th 코드 로그 · React Hooks: useMemo

허정석·2025년 7월 21일

TIL

목록 보기
7/19
post-thumbnail

useMemo

🖥️ 구현 코드

import type { DependencyList } from "react";
import { shallowEquals } from "../equals";
import { useRef } from "./useRef";

export function useMemo<T>(factory: () => T, _deps: DependencyList, _equals = shallowEquals): T {
  // 단 한 번만 초기화
  const memoizatedRef = useRef<{ deps: DependencyList; result: T } | null>(null);

  if (memoizatedRef.current === null || !_equals(memoizatedRef.current.deps, _deps)) {
    // 새로운 값으로 업데이트 (랜더링을 유발하지 않는 방식)
    memoizatedRef.current = { deps: _deps, result: factory() };
  }
  // 저장된 result 반환
  return memoizatedRef.current.result;
}

📘 work-log

work-log


🤖 Gemini 설명문

useMemo는 다음과 같은 4가지의 뚜렷한 성격을 가지고 있습니다.

1. "게으르지만 효율적"

useMemo의 가장 핵심적인 성격입니다. 이 함수는 계산(factory 함수 실행)을 최대한 피하려고 합니다.
꼭 필요할 때만, 단 한 번만 계산합니다.

  • 코드 증거: factory() 호출이 if 블록 안에 있다는 것.
   1     if (/* 조건 */) {
   2       // 조건에 합당 해야지만 factory 실행
   3       memoizatedRef.current = { deps: _deps, result: factory() };
   4     }

if 조건(처음이거나, 의존성이 바뀌었을 때)이 충족되지 않으면, factory()는 실행 되지 않음.
이는 비싼 계산을 건너뛰어 애플리케이션의 성능을 높여주는 useMemo의 존재 이유

2. "결과만 기억하고 과정은 잊는다"

useMemo는 factory 함수를 실행한 결과값은 간직하지만, 그 결과를 만들어낸 과정(factory 함수 자체)은 기억하지 않습니다.

  • 코드 증거: memoizatedRef의 타입과 저장하는 값.
   1     // 저장하는 것: deps와 result
   2     useRef<{ deps: DependencyList; result: T } | null>(null);
   3 
   4     // ...
   5 
   6     // 저장소에 factory 함수 자체를 넣는 코드는 없음.
   7     memoizatedRef.current = { deps: _deps, result: factory() };

useRef 상자 안에는 deps와 result만 저장됩니다. 이 때문에 useMemo를 호출할 때마다 매번 factory 함수를 인자로 넘겨줘야 하는 것입니다.
"factory 써볼까... 뭐야.. 전이랑 지금이랑 달라진게 없네? 그럼 그냥 있던 거 쓰자" 라고 알려주는 것.

3. "얕은 기억력의 소유자"

기본적으로 useMemo는 의존성 배열에 들어있는 객체나 배열의 속까지 들여다보지 않습니다.
겉모습(참조값)만 보고 "어? 다른 값이네!"라고 섣불리 판단하는 경향이 있습니다.

  • 코드 증거: 함수의 세 번째 인자에 있는 기본값 _equals = shallowEquals.
   1     export function useMemo<T>(..., _equals =
     shallowEquals): T { ... }

shallowEquals는 객체나 배열의 내용이 같더라도, 메모리 주소가 다르면 다르다고 판단합니다.
그래서 useMemo(() => {...}, [{}]) 와 같은 코드가 매번 재실행되는 것입니다.
이 "얕은 기억력"은 useMemo를 사용할 때 가장 주의해야 할 특징 중 하나입니다.

4. "유연한 판단 기준"

useMemo는 기본적으로 얕은 기억력을 가졌지만, 사용자가 원한다면 "판단 기준"을 바꿀 수 있는 유연함도 갖추고 있습니다.

  • 코드 증거: 세 번째 인자 _equals를 외부에서 주입받을 수 있음.
   1     export function useMemo<T>(..., _equals = shallowEquals): T {
   2       // ...
   3       if (... || !_equals(memoizatedRef.current.deps, _deps)) { ... }
   4       // ...
   5     }

useMemo는 자기가 가진 shallowEquals만 고집하지 않습니다.
사용자가 deepEquals나 다른 커스텀 비교 함수를 _equals 인자로 넣어주면, 그 함수를 사용해 의존성을 비교 합니다.
이는 useMemo를 더 강력하고 다양한 상황에 대처할 수 있게 만들어주는 매우 실용적인 성격입니다.

0개의 댓글