성능 코딩 가이드라인
핵심 원칙
"측정 없이 최적화하지 않는다."
memo, useMemo, useCallback, lazy는 모두 코드 복잡도를 올린다. 이 비용을 정당화할 수 있는 근거가 있을 때만 사용한다.
즉시 방지해야 하는 문제 (Tier 1)
렌더링 루프
- •useEffect 의존성 배열에 매 렌더마다 새로 생성되는 참조(객체, 배열)를 넣지 않는다
- •부모-자식 간 상태 동기화로 인한 연쇄 렌더링을 피한다
메모리 누수
- •useEffect에서 등록한 이벤트 리스너, 타이머, 구독은 반드시 cleanup한다
번들 포함 실수
- •moment.js 전체 로케일 로딩 등 대형 라이브러리의 무분별한 import 금지
- •미사용 대형 라이브러리를 번들에 포함하지 않는다
조건부 적용 (Tier 2)
아래는 규모에 따라 판단한다. 소규모면 적용하지 않는다:
| 상황 | 적용 기준 |
|---|---|
| 리스트 가상화 | 항목 100개 이상 될 수 있을 때만 |
| Context 분리 | 소비자가 5개 이상일 때만 |
| useMemo | O(n²) 이상 복잡도일 때만 |
| 코드 스플리팅 | 해당 모듈 50KB 이상이거나 초기 로딩에 불필요할 때만 |
사용하지 않는 최적화 (Tier 3)
명확한 병목이 입증되지 않는 한 적용하지 않는다:
- •단순 컴포넌트에 React.memo 래핑
- •props가 primitive인 함수에 useCallback
- •단순 계산(필터링, 매핑 등 O(n))에 useMemo
- •소규모 리스트(50개 미만)에 가상화
- •사용자 인터랙션 빈도가 낮은 컴포넌트의 리렌더 최적화
불필요한 최적화 제거
아래 패턴을 발견하면 제거한다:
- •deps 배열이 매 렌더마다 변경되는 useMemo/useCallback (의미 없는 메모이제이션)
- •자식이 없거나 단순한 컴포넌트의 React.memo
- •한 번만 실행되는 연산의 useMemo
- •실제로 사용되지 않는 code splitting (오히려 로딩 워터폴 유발)