콘텐츠로 이동

성능 최적화 (Performance)

React 앱이 무거워지는 주된 원인은 불필요한 리렌더링, 큰 번들, 그리고 느린 데이터 패치입니다. 데이터스케쳐스 실무 관점에서 정리합니다.

렌더링 비용 이해하기

  • 렌더(Render)는 컴포넌트 함수를 호출해 가상 DOM 트리를 만드는 단계입니다. 실제 DOM 변경은 재조정(reconciliation)이 diff 를 낼 때만 일어납니다.
  • 부모가 리렌더링되면 기본적으로 모든 자식도 리렌더링됩니다. props 가 안 바뀌어도 자식이 다시 그려지는 게 핵심 낭비입니다.

메모이제이션: React.memo / useMemo / useCallback

  • React.memo(Component): props 가 바뀌지 않으면 자식 리렌더링을 건너뜁니다.
  • useMemo: 계산 비싼 값을 캐시합니다.
  • useCallback: 함수 참조를 안정화해, memo 화된 자식의 props 항등성을 유지합니다.
const sorted = useMemo(() => expensiveSort(items), [items]);
const onSelect = useCallback((id) => setSelected(id), []);
return <MemoizedList items={sorted} onSelect={onSelect} />;
  • 주의: 메모이제이션은 힌트이지 정답이 아닙니다. 프로파일로 실제 병목을 확인한 뒤에만 적용해야 오버헤드만 늘지 않습니다.

구조적 최적화 (가장 효과적)

  • 상태를 아래로 내리기: 검색 입력 상태를 페이지가 아니라 검색 박스 안에 두면 키 입력마다 페이지 전체가 리렌더링되지 않습니다.
  • children 패턴: 빠르게 변하는 컴포넌트가 무거운 자식을 props 로 받되, 자식은 부모가 아니라 외부에서 생성된 요소라면 리렌더링되지 않습니다.
  • 코드 분할(Code Splitting): React.lazy + Suspense 로 초기 번들을 줄이고 LCP(Largest Contentful Paint) 를 개선합니다.
const Report = React.lazy(() => import('./Report'));

React Compiler (React 19+)

  • React 19 의 React Compiler 는 빌드 타임에 useMemo/useCallback 을 자동으로 적용해, 수동 메모이제이션을 대부분 생략하게 해줍니다. 적용 후 성능을 프로파일로 검증하고 수동 최적화는 점진적으로 제거하세요.

데이터스케쳐스 실무 관점

  • 대시보드/통계 화면: 자주 변하는 필터 상태를 아래로 내리고, 무거운 차트는 코드 분할로 지연 로드합니다.
  • 측정 먼저: Chrome DevTools Profiler 나 React DevTools 로 실제로 쓸데없이 그려지는 구간을 찾은 뒤, 해당 컴포넌트만 최적화합니다.

확인 필요

  • React Compiler 지원 범위와 규칙(Rules of React)은 React 버전별로 다르므로, 사용하는 버전의 공식 문서를 재확인하세요. (확인 필요)

더 알아보기