React 성능 최적화 — memo · useMemo · useCallback
잘못 쓰면 오히려 손해. 측정 후 정확한 위치에 한 번씩만.
"React 가 느려요" 라는 질문에 90% 의 답은 — "진짜 느린지 측정부터". memo·useMemo·useCallback 을 모든 컴포넌트에 박는 건 안티패턴. 메모이제이션 자체도 비용이 있고, dependency 비교가 매 렌더 추가된다.
이번 16편은 3개 메모 도구의 정확한 동작 + 언제 써야 하고 언제 쓰지 말아야 하는지 + React Compiler (2025) 가 바꾸는 패러다임까지. 이걸 정확히 알면 React 가 빨라지는 게 아니라 빠른 React 를 망치지 않게 된다.
1. React 의 재렌더 모델 — 왜 최적화가 필요한가
React 기본 동작 — 부모가 재렌더되면 자식 전부 재렌더. props 가 안 바뀌어도. 대부분 빠르지만 무거운 컴포넌트 (큰 리스트·복잡 차트) 가 자식에 있으면 부모의 사소한 state 변화에 전부 재계산.
HeavyList 가 props 도 안 받는데 부모 state 바뀔 때마다 다시 그려진다. 여기에 memo 가 답.
2. memo — 컴포넌트의 재렌더 스킵
memo 로 감싸면 React 가 props 를 얕은 비교 — 모든 prop 이 이전과 같으면 (참조 동일) 재렌더 스킵.
<HeavyList items={items.filter(...)} onClick={() => doSomething()} /> 같은 코드는 memo 가 있어도 매번 재렌더.
3. useMemo · useCallback — 참조 안정화
memo 의 함정 해결책. 객체/배열은 useMemo, 함수는 useCallback 으로 참조 유지.
이 두 Hook 의 dependency 배열은 useEffect (11편) 와 동일 — 안에서 쓰는 값을 모두 포함. ESLint 가 자동 검사.
4. 사용 가이드 — 4 신호 + 측정 우선
실전에서 메모 도구를 박을 만한 4 신호.
| 도구 | 박을 신호 |
|---|---|
| memo | 자식 컴포넌트가 무거운데 부모가 자주 재렌더 (예: 입력 도중 매 키마다 차트 다시 그림) |
| useMemo | 계산 자체가 비싼 경우 (큰 리스트 정렬·필터·복잡 수식). 또는 그 결과를 memo 자식에 props 로 전달 |
| useCallback | 함수를 memo 자식에 props 로 전달. 또는 useEffect dependency 로 사용 |
| 박지 말 것 | 정상 속도. memo 의 비교 비용이 재렌더 비용보다 클 수 있음. "혹시 모르니" 박지 말 것 |
5. React Compiler — 곧 위 3개가 불필요해진다
2024~2025 년 가장 큰 변화 — React Compiler (a.k.a. React Forget). 컴파일 시점에 자동으로 memoization 을 삽입. 개발자가 useMemo·useCallback·memo 를 박을 필요 없이 컴파일러가 알아서.
현재 (2026 년) — Meta·Instagram 내부에서 production 사용 중, OSS 는 stable 향해 진행. Next.js 15+ 와 Vite 플러그인 모두 옵트인 지원. 단계적으로 옵트인하다 결국 디폴트가 될 듯.
16편으로 React 의 핵심 8개 (5편 props · 6 state · 11 effect · 12 hook · 13 context · 14 reducer · 15 router · 16 perf) 가 정리됐다. 17편부터는 데이터 fetch 의 모던 표준 — Suspense + TanStack Query 로.
다음 글
React 교재 17편 — Suspense + 데이터 fetch. TanStack Query 로 useEffect fetch 의 진짜 졸업.