핵심 요약
useMemo/useCallback은 공짜가 아니다(비교 비용+메모리). 의미 있는 경우는 둘뿐 — ① 렌더마다 도는 비싼 계산을 캐싱할 때, ② React.memo로 감싼 자식에게 넘기는 객체·함수 참조를 안정화할 때. 그 외엔 그냥 쓰지 마라.
1. 셋의 역할
| API | 캐싱 대상 | 주 용도 |
|---|---|---|
| React.memo | 컴포넌트 렌더 결과 | props 같으면 리렌더 skip |
| useMemo | 계산된 값 | 비싼 계산·참조 안정화 |
| useCallback | 함수 참조 | memo 자식에 콜백 전달 |
2. 쓸 가치가 있는 경우
// 1) 비싼 계산
const sorted = useMemo(() => bigList.sort(cmp), [bigList])
// 2) memo된 자식에 넘기는 콜백
const Child = React.memo(Inner)
const onClick = useCallback(() => doX(id), [id])
return <Child onClick={onClick} />
3. 함정
- 자식이 memo가 아니면 useCallback은 무의미 — 참조만 고정될 뿐 리렌더는 그대로
- 원시값(숫자·문자)을 useMemo로 감싸는 건 낭비
- 의존성 배열이 틀리면 stale 값으로 더 큰 버그
자주 묻는 질문
일단 다 useMemo로 감싸면 빨라지나요?
아니요. 비교·메모리 비용이 추가돼 보통은 더 느려지거나 비슷합니다. 측정 없이 남발하지 말고, React DevTools Profiler로 실제 병목을 찾은 뒤 적용하세요.
React 19의 컴파일러가 있으면 필요 없나요?
React Compiler가 자동 메모이제이션을 많이 대신해 줍니다. 도입했다면 수동 useMemo/useCallback은 대폭 줄여도 됩니다. 다만 아직 모든 프로젝트가 쓰는 건 아닙니다.

댓글 0