11th 코드로그 · Higher-Order Component - HOC: memo

허정석·2025년 7월 23일

TIL

목록 보기
11/19
post-thumbnail

memo

🖥️ 구현 코드

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

export function memo<P extends object>(Component: FunctionComponent<P>, equals = shallowEquals) {
  // 새로운 컴포넌트 정의, 렌더링 할 때 props 넘겨줌.
  const memoizatedComponent: FunctionComponent<P> = (props) => {
    const cache = useRef<{ preProps: P; result: React.ReactElement } | null>(null);
    // 최초 렌더링 또는 props 변경 시 컴포넌트 호출하여 렌더링 값 설정
    if (cache.current === null || !equals(cache.current.preProps, props)) {
      const newResult = Component(props);
      cache.current = { preProps: props, result: newResult };
    }
    return cache.current.result;
  };
  return memoizatedComponent;
}

📘 work-log

work-log


🤖 Gemini 설명문

궁금증 정리

  • 코드 분석
const cache = useRef<{ preProps: P; result: React.ReactElement } | null>(null);

...

if (cache.current === null || !equals(cache.current.preProps, props)) {
  const newResult = Component(props);
  cache.current = { preProps: props, result: newResult };
}
  1. prevProps: P:
  • P는 memo 함수에 전달된 Component가 받을 props의 타입입니다. 예를 들어 Component가 { name: string } 타입의 props를 받는다면, P는 { name: string }이 됩니다.
  • prevProps는 이전 렌더링 시 사용했던 props를 저장하는 공간이므로,
    원본 컴포넌트의 props 타입과 동일해야 합니다.
    이렇게 함으로써 prevProps에 접근할 때 TypeScript가 올바른 속성(예: cache.current.prevProps.name)을 추론하고, 잘못된 타입의 값을 할당하는 것을 방지합니다.

    💡 P는 "아직 정해지지 않은, 어떤 객체 타입"을 나타내는 자리표시자(placeholder)

  1. result: React.ReactElement:
  • React 함수 컴포넌트가 반환하는 값은 JSX 엘리먼트(예: <div>Hello</div>)이며, 이는 React 내부적으로 React.ReactElement 타입으로 표현됩니다.
  • result는 Component(props)를 호출하여 얻은 렌더링 결과(JSX) 를 저장하는 공간입니다. 이 결과를 정확한 타입으로 명시함으로써,
    나중에 이 result를 반환할 때 React가 올바른 타입의 엘리먼트를 받도록 보장합니다.
  1. | null:

    • useRef의 초기값으로 null을 주었기 때문에, cache.current는 처음에는 null이 됩니다.
    • 따라서 cache.current가 null일 수도 있다는 것을 TypeScript에 알려주기 위해 | null을 붙여줍니다. 이렇게 하면 cache.current를 사용하기 전에 null 체크를 강제하여 런타임 오류를 방지할 수 있습니다.
  1. Component(props)를 호출하여 렌더링한 값을 result에 넣는 이유:
    메모이제이션(Memoization) 의 핵심

    • Component(props)를 호출하는 것은 해당 컴포넌트의 JSX를 계산하고 가상 DOM 트리를 만드는 과정 ➡️ 비용이 많이 발생.
    • 초기 또는 props 변경처럼 필요에 의해 렌더링하여 불필요한 재렌더링을 방지하기 위한 전략

0개의 댓글