React Native 모범 사례
개요
React Native 애플리케이션을 위한 성능 최적화 가이드입니다. JavaScript/React, 네이티브(iOS/Android), 번들링 최적화를 다룹니다. Callstack의 "Ultimate Guide to React Native Optimization"을 기반으로 합니다.
적용 시기
다음과 같은 상황에서 이 가이드라인을 참조하세요:
- 느리거나 버벅거리는 UI 또는 애니메이션 디버깅
- 메모리 누수(JS 또는 네이티브) 조사
- 앱 시작 시간(TTI) 최적화
- 번들 또는 앱 크기 감소
- 네이티브 모듈(Turbo Modules) 작성
- React Native 성능 프로파일링
- 성능 관점에서 React Native 코드 검토
보안 참고 사항
- 이 문서의 셸 명령어는 로컬 개발자 작업으로 간주하세요. 실행 전에 검토하고, 버전이 고정된 도구를 선호하며, 원격 스크립트를 셸에 직접 파이프하는 것을 피하세요.
- 서드파티 라이브러리와 플러그인은 일반적인 공급망 관리가 필요한 의존성으로 취급하세요: 버전 고정, 출처 확인, 표준 검토 프로세스를 통한 업데이트.
- 원격 청크 로딩은 자사 아티팩트 전용으로만 처리하세요. 앱에 번들된 청크나 서명된 CI 릴리스 매니페스트를 선호하며, 호스팅된 청크는 신뢰할 수 있는 HTTPS 출처에서 제공되고 현재 앱 릴리스에 고정되어야 합니다.
우선순위 순서 가이드라인
| 우선순위 | 카테고리 | 영향도 | 접두사 |
|---|---|---|---|
| 1 | FPS 및 리렌더링 | CRITICAL | js-* |
| 2 | 번들 크기 | CRITICAL | bundle-* |
| 3 | TTI 최적화 | HIGH | native-*, bundle-* |
| 4 | 네이티브 성능 | HIGH | native-* |
| 5 | 메모리 관리 | MEDIUM-HIGH | js-*, native-* |
| 6 | 애니메이션 | MEDIUM | js-* |
영향도 레이블은 트라이지 힌트입니다: CRITICAL을 먼저, 그 다음 HIGH, 증거가 해당 방향을 가리킬 때 MEDIUM을 처리하세요.
빠른 참조
최적화 워크플로우
모든 성능 문제에 대해 다음 사이클을 따르세요: 측정 → 최적화 → 재측정 → 검증
- 측정: 변경 전 기준 메트릭을 캡처합니다. 런타임 문제의 경우, 가능할 때 커밋 타임라인, 리렌더링 횟수, 느린 컴포넌트, 가장 무거운 커밋 분석, 시작/TTI를 선호합니다. 컴포넌트 트리 깊이나 개수는 선택적 맥락일 뿐 대체재가 아닙니다. 측정된 렌더링이나 FPS 문제 없이 메모이제이션, 원자 상태 또는 컴파일러 변경을 추천하지 마세요.
- 최적화: 관련 참조에서 대상 수정 사항을 적용합니다.
- 재측정: 동일한 측정을 실행하여 업데이트된 메트릭을 얻습니다.
- 검증: 개선 확인 (예: FPS 45→60, TTI 3.2초→1.8초, 번들 2.1MB→1.6MB).
메트릭이 개선되지 않은 경우 변경 사항을 되돌리고 다음 제안된 수정을 시도하세요.
검토 가드레일
- API별 수정을 제안하기 전에 라이브러리 버전을 확인하세요. 예: FlashList v2는
estimatedItemSize를 더 이상 사용하지 않으므로 누락된 것으로 표시하지 마세요. - 동작이 명백히 잘못되었거나 프로파일링이 해당 값과 관련된 불필요한 작업을 보여주지 않는 한
useMemo또는useCallback의존성 변경을 제안하지 마세요. - 추측성으로 클로저 스테일을 보고하지 마세요. 스테일 읽기 경로, 재현 또는 프로파일러 증거를 먼저 제시하세요.
- 플로우를 프로파일링할 때 대상 상호작용 자체를 측정하세요. 컴포넌트 트리 깊이나 컴포넌트 개수를 주요 성능 증거로 취급하지 마세요.
중요: FPS 및 리렌더링
먼저 프로파일링:
agent-device react-devtools status
agent-device react-devtools wait --connected
agent-device react-devtools profile start
agent-device react-devtools profile stop
agent-device react-devtools profile slow --limit 5
agent-device react-devtools profile rerenders --limit 5
agent-device react-devtools profile timeline --limit 20
profile start와 profile stop 사이에 일반 agent-device 명령어로 대상 상호작용을 구동하세요.
agent-device를 사용할 수 없을 때 수동 대체: Metro (j) 또는 Dev Menu에서 React Native DevTools를 열고, Profiler 탭을 사용하여 동일한 상호작용을 기록하세요.
릴리스 빌드 React 컴포넌트 프로파일링의 경우, 먼저 @callstack/inspector를 연결하여 React DevTools가 릴리스 앱에 연결되도록 한 다음 위의 agent-device react-devtools 흐름을 실행하세요.
일반적인 수정 사항:
- 긴 목록의 경우 ScrollView를 FlatList/FlashList/Legend List로 교체
- 프로파일링 후 계단식 리렌더링이 확인되면 React Compiler를 사용하여 자동 메모이제이션 적용
- 프로파일링 후 광범위한 스토어/컨텍스트 업데이트가 확인되면 원자 상태(Jotai/Zustand)를 사용하여 리렌더링 감소
- 값비싼 계산에
useDeferredValue사용
중요: 번들 크기
번들 분석:
npx react-native bundle \
--entry-file index.js \
--bundle-output output.js \
--platform ios \
--sourcemap-output output.js.map \
--dev false --minify true
npx source-map-explorer output.js --no-border-checks
최적화 후 개선 확인:
# 변경 전 기준 크기 기록
ls -lh output.js # 예: 변경 전: 2.1 MB
# 수정 적용 후 재번들링 및 비교
npx react-native bundle --entry-file index.js --bundle-output output.js \
--platform ios --dev false --minify true
ls -lh output.js # 예: 변경 후: 1.6 MB (24% 감소)
일반적인 수정 사항:
- 배럴 임포트 피하기 (소스에서 직접 임포트)
- Hermes API 및 메서드 적용 범위 확인 후 불필요한 Intl 폴리필 제거
- 트리 쉐이킹 평가 (Expo SDK 52+ 실험적 미사용 import/export 제거, 또는 이미 구성된 경우 Re.Pack)
- Android 네이티브 코드 축소를 위해 R8 활성화
높음: TTI 최적화
TTI 측정:
react-native-performance사용하여 마커 설정- 콜드 스타트만 측정 (웜/핫/프리워밍 제외)
일반적인 수정 사항:
- React Native 0.78 이하의 경우 Android JS 번들 압축을 비활성화하여 Hermes mmap 활성화
- 네이티브 내비게이션 사용 (react-native-screens)
- 자주 사용되는 값비싼 화면을 탐색하기 전에 사전 로드
높음: 네이티브 성능
네이티브 프로파일링:
- iOS: Xcode Instruments → Time Profiler
- Android: Android Studio → CPU Profiler
일반적인 수정 사항:
- 무거운 네이티브 작업에 백그라운드 스레드 사용
- 동기식 Turbo Module 메서드보다 비동기식 선호
- 크로스 플랫폼 성능이 중요한 코드에 C++ 사용
참조
전체 문서 및 코드 예제는 references/에 있습니다:
JavaScript/React (js-*)
| 파일 | 영향도 | 설명 |
|---|---|---|
| js-lists-flatlist-flashlist.md | CRITICAL | ScrollView를 가상화된 목록으로 교체 |
| js-profile-react.md | MEDIUM | agent-device react-devtools 프로파일링 |
| js-measure-fps.md | HIGH | FPS 모니터링 및 측정 |
| js-memory-leaks.md | MEDIUM | JS 메모리 누수 탐지 |
| js-atomic-state.md | HIGH | Jotai/Zustand 패턴 |
| js-concurrent-react.md | HIGH | useDeferredValue, useTransition |
| js-react-compiler.md | HIGH | 자동 메모이제이션 |
| js-animations-reanimated.md | MEDIUM | Reanimated worklets |
| js-bottomsheet.md | HIGH | Bottom sheet 최적화 |
| js-uncontrolled-components.md | HIGH | TextInput 최적화 |
네이티브 (native-*)
| 파일 | 영향도 | 설명 |
|---|---|---|
| native-turbo-modules.md | HIGH | 빠른 네이티브 모듈 구축 |
| native-sdks-over-polyfills.md | HIGH | 네이티브 vs JS 라이브러리 |
| native-measure-tti.md | HIGH | TTI 측정 설정 |
| native-threading-model.md | HIGH | Turbo Module 스레드 |
| native-profiling.md | MEDIUM | Xcode/Android Studio 프로파일링 |
| native-platform-setup.md | MEDIUM | iOS/Android 도구 가이드 |
| native-view-flattening.md | MEDIUM | 뷰 계층 구조 디버깅 |
| native-memory-patterns.md | MEDIUM | C++/Swift/Kotlin 메모리 |
| native-memory-leaks.md | MEDIUM | 네이티브 메모리 누수 탐지 |
| native-android-16kb-alignment.md | CRITICAL | Google Play용 서드파티 라이브러리 정렬 |
번들링 (bundle-*)
| 파일 | 영향도 | 설명 |
|---|---|---|
| bundle-barrel-exports.md | CRITICAL | 배럴 임포트 피하기 |
| bundle-analyze-js.md | CRITICAL | JS 번들 시각화 |
| bundle-tree-shaking.md | HIGH | 데드 코드 제거 |
| bundle-analyze-app.md | HIGH | 앱 크기 분석 |
| bundle-r8-android.md | HIGH | Android 코드 축소 |
| bundle-hermes-mmap.md | HIGH | 번들 압축 비활성화 |
| bundle-native-assets.md | HIGH | 에셋 카탈로그 설정 |
| bundle-library-size.md | MEDIUM | 의존성 평가 |
| bundle-code-splitting.md | MEDIUM | 원격 청크 로딩 보호 장치 |
문제 → 스킬 매핑
| 문제 | 시작 항목 |
|---|---|
| 앱이 느리거나 버벅거림 | js-measure-fps.md → js-profile-react.md |
| 너무 많은 리렌더링 | js-profile-react.md → js-react-compiler.md |
| 느린 시작 (TTI) | native-measure-tti.md → bundle-analyze-js.md |
| 큰 앱 크기 | bundle-analyze-app.md → bundle-r8-android.md |
| 메모리 증가 | js-memory-leaks.md 또는 native-memory-leaks.md |
| 애니메이션 프레임 드랍 | js-animations-reanimated.md |
| Bottom sheet 버벅거림/리렌더링 | js-bottomsheet.md → js-animations-reanimated.md |
| 목록 스크롤 버벅거림 | js-lists-flatlist-flashlist.md |
| TextInput 지연 | js-uncontrolled-components.md |
| 네이티브 모듈 느림 | native-turbo-modules.md → native-threading-model.md |
| 네이티브 라이브러리 정렬 문제 | native-android-16kb-alignment.md |
기여
Callstack의 "The Ultimate Guide to React Native Optimization"을 기반으로 합니다.