React의 메모이제이션(Memoization) 도구 셋은 모두 "입력이 같으면 이전 결과를 재사용"하는 캐시지만 대상이 다르다. useMemo는 계산한 값, useCallback은 함수, React.memo는 컴포넌트의 렌더 결과를 캐시한다.
React.memo(Child)는 props를 얕게(Shallow Comparison,Object.is) 비교해 같으면 렌더를 건너뛴다- 객체·배열·함수는 렌더마다 새 참조로 다시 만들어진다. 그래서 memo된 자식에게 넘길 때
useMemo·useCallback으로 참조를 고정해야 비교가 통과한다. 셋이 맞물려야 효과가 난다 - 오해: props를 메모한다고 자식 리렌더가 막히지 않는다. 부모가 다시 렌더하면 자식도 렌더한다. props 메모가 의미 있는 건 자식이
memo로 감싸져 있거나, 그 값이 자식 훅의 의존성으로 쓰일 때뿐이다
메모가 깨지는 흔한 경우
<Child {...props} />로 펼쳐 넘기면 어떤 참조가 새로 만들어지는지 관리하기 어렵다children도 prop이다.<Memo><div>내용</div></Memo>는 렌더마다 새 children을 넘겨 memo가 무의미해진다
언제 쓰나
memo: 같은 props에 같은 결과를 내고 렌더 비용이 큰 컴포넌트. 프로파일러로 병목을 확인한 뒤에useMemo: 측정해 보니 비싼 계산, 또는 memo된 자식·Effect 의존성에 넘길 객체useCallback: memo된 자식이나 Effect 의존성에 넘길 함수- 바뀌지 않는 JSX(로딩 스켈레톤, 큰 정적 SVG(Scalable Vector Graphics))는 컴포넌트 밖 상수로 끌어올려 재사용할 수 있다. 효과는 작다
메모부터 붙이기 전에 구조를 바꿔 리렌더 범위를 줄이는 게 먼저다(상태 내리기와 컴포지션으로 리렌더 줄이기, 섣부른 최적화). 2026년 기준으로는 React Compiler가 이 작업 대부분을 자동으로 해 주고, 수동 메모는 컴파일러가 건너뛴 곳 같은 예외에만 남긴다. 비교 알고리즘 자체는 재조정(Reconciliation).