react-native-best-practices12.1 KB
View saved version →
---
name: react-native-best-practices
description: Provides React Native performance optimization guidelines for FPS, TTI, bundle size, memory leaks, re-renders, and animations. Applies to tasks involving Hermes optimization, JS thread blocking, bridge overhead, FlashList, native modules, or debugging jank and frame drops.
license: MIT
---
# React Native Best Practices
## Overview
Performance optimization guide for React Native applications, covering JavaScript/React, Native (iOS/Android), and bundling optimizations. Based on Callstack's "Ultimate Guide to React Native Optimization".
## When to Apply
Reference these guidelines when:
- Debugging slow/janky UI or animations
- Investigating memory leaks (JS or native)
- Optimizing app startup time (TTI)
- Reducing bundle or app size
- Writing native modules (Turbo Modules)
- Profiling React Native performance
- Reviewing React Native code for performance
## Security Notes
- Treat shell commands in these references as local developer operations. Review them before running, prefer version-pinned tooling, and avoid piping remote scripts directly to a shell.
- Treat third-party libraries and plugins as dependencies that still require normal supply-chain controls: pin versions, verify provenance, and update through your standard review process.
- Treat remote chunk loading as first-party artifact delivery only. Prefer app-bundled chunks or signed CI release manifests; hosted chunks must come from trusted HTTPS origins you control and be pinned to the current app release.
## Priority-Ordered Guidelines
| Priority | Category | Impact | Prefix |
|----------|----------|--------|--------|
| 1 | FPS & Re-renders | CRITICAL | `js-*` |
| 2 | Bundle Size | CRITICAL | `bundle-*` |
| 3 | TTI Optimization | HIGH | `native-*`, `bundle-*` |
| 4 | Native Performance | HIGH | `native-*` |
| 5 | Memory Management | MEDIUM-HIGH | `js-*`, `native-*` |
| 6 | Animations | MEDIUM | `js-*` |
Impact labels are triage hints: CRITICAL first, HIGH next, MEDIUM when evidence points there.
## Quick Reference
### Optimization Workflow
Follow this cycle for any performance issue: **Measure → Optimize → Re-measure → Validate**
1. **Measure**: Capture baseline metrics before changes. For runtime issues, prefer commit timeline, re-render counts, slow components, heaviest-commit breakdown, and startup/TTI when available. Component tree depth or count are optional context, not substitutes. Do not recommend memoization, atomic state, or compiler changes without a measured render or FPS problem.
2. **Optimize**: Apply the targeted fix from the relevant reference
3. **Re-measure**: Run the same measurement to get updated metrics
4. **Validate**: Confirm improvement (e.g., FPS 45→60, TTI 3.2s→1.8s, bundle 2.1MB→1.6MB)
If metrics did not improve, revert and try the next suggested fix.
### Review Guardrails
- Check library versions before suggesting API-specific fixes. Example: FlashList v2 deprecates `estimatedItemSize`, so do not flag it as missing there.
- Do not suggest `useMemo` or `useCallback` dependency changes unless behavior is demonstrably incorrect or profiling shows wasted work tied to that value.
- Do not report stale closures speculatively. Show the stale read path, a repro, or profiler evidence before calling it out.
- When profiling a flow, measure the target interaction itself. Do not treat component tree depth or component count as the main performance evidence.
### Critical: FPS & Re-renders
**Profile first:**
```bash
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
```
Drive the target interaction with normal `agent-device` commands between `profile start` and `profile stop`.
Manual fallback when `agent-device` is unavailable: open React Native DevTools from Metro (`j`) or the Dev Menu, use the Profiler tab, and record the same interaction.
For release-build React component profiling, connect [`@callstack/inspector`](https://github.com/callstackincubator/inspector#inspector) first so React DevTools can attach to the release app, then run the `agent-device react-devtools` flow above.
**Common fixes:**
- Replace ScrollView with FlatList/FlashList/Legend List for long lists
- After profiling shows cascading re-renders, use React Compiler for automatic memoization
- After profiling shows broad store/context updates, use atomic state (Jotai/Zustand) to reduce re-renders
- Use `useDeferredValue` for expensive computations
### Critical: Bundle Size
**Analyze bundle:**
```bash
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
```
**Verify improvement after optimization:**
```bash
# Record baseline size before changes
ls -lh output.js # e.g., Before: 2.1 MB
# After applying fixes, re-bundle and compare
npx react-native bundle --entry-file index.js --bundle-output output.js \
--platform ios --dev false --minify true
ls -lh output.js # e.g., After: 1.6 MB (24% reduction)
```
**Common fixes:**
- Avoid barrel imports (import directly from source)
- Remove unnecessary Intl polyfills only after checking Hermes API and method coverage
- Evaluate tree shaking (Expo SDK 52+ experimental unused import/export removal, or Re.Pack only if already configured)
- Enable R8 for Android native code shrinking
### High: TTI Optimization
**Measure TTI:**
- Use `react-native-performance` for markers
- Only measure cold starts (exclude warm/hot/prewarm)
**Common fixes:**
- For React Native 0.78 and earlier, disable Android JS bundle compression to enable Hermes mmap
- Use native navigation (react-native-screens)
- Preload commonly-used expensive screens before navigating to them
### High: Native Performance
**Profile native:**
- iOS: Xcode Instruments → Time Profiler
- Android: Android Studio → CPU Profiler
**Common fixes:**
- Use background threads for heavy native work
- Prefer async over sync Turbo Module methods
- Use C++ for cross-platform performance-critical code
## References
Full documentation with code examples in [references/][references]:
### JavaScript/React (`js-*`)
| File | Impact | Description |
|------|--------|-------------|
| [js-lists-flatlist-flashlist.md][js-lists-flatlist-flashlist] | CRITICAL | Replace ScrollView with virtualized lists |
| [js-profile-react.md][js-profile-react] | MEDIUM | `agent-device react-devtools` profiling |
| [js-measure-fps.md][js-measure-fps] | HIGH | FPS monitoring and measurement |
| [js-memory-leaks.md][js-memory-leaks] | MEDIUM | JS memory leak hunting |
| [js-atomic-state.md][js-atomic-state] | HIGH | Jotai/Zustand patterns |
| [js-concurrent-react.md][js-concurrent-react] | HIGH | useDeferredValue, useTransition |
| [js-react-compiler.md][js-react-compiler] | HIGH | Automatic memoization |
| [js-animations-reanimated.md][js-animations-reanimated] | MEDIUM | Reanimated worklets |
| [js-bottomsheet.md][js-bottomsheet] | HIGH | Bottom sheet optimization |
| [js-uncontrolled-components.md][js-uncontrolled-components] | HIGH | TextInput optimization |
### Native (`native-*`)
| File | Impact | Description |
|------|--------|-------------|
| [native-turbo-modules.md][native-turbo-modules] | HIGH | Building fast native modules |
| [native-sdks-over-polyfills.md][native-sdks-over-polyfills] | HIGH | Native vs JS libraries |
| [native-measure-tti.md][native-measure-tti] | HIGH | TTI measurement setup |
| [native-threading-model.md][native-threading-model] | HIGH | Turbo Module threads |
| [native-profiling.md][native-profiling] | MEDIUM | Xcode/Android Studio profiling |
| [native-platform-setup.md][native-platform-setup] | MEDIUM | iOS/Android tooling guide |
| [native-view-flattening.md][native-view-flattening] | MEDIUM | View hierarchy debugging |
| [native-memory-patterns.md][native-memory-patterns] | MEDIUM | C++/Swift/Kotlin memory |
| [native-memory-leaks.md][native-memory-leaks] | MEDIUM | Native memory leak hunting |
| [native-android-16kb-alignment.md][native-android-16kb-alignment] | CRITICAL | Third-party library alignment for Google Play |
### Bundling (`bundle-*`)
| File | Impact | Description |
|------|--------|-------------|
| [bundle-barrel-exports.md][bundle-barrel-exports] | CRITICAL | Avoid barrel imports |
| [bundle-analyze-js.md][bundle-analyze-js] | CRITICAL | JS bundle visualization |
| [bundle-tree-shaking.md][bundle-tree-shaking] | HIGH | Dead code elimination |
| [bundle-analyze-app.md][bundle-analyze-app] | HIGH | App size analysis |
| [bundle-r8-android.md][bundle-r8-android] | HIGH | Android code shrinking |
| [bundle-hermes-mmap.md][bundle-hermes-mmap] | HIGH | Disable bundle compression |
| [bundle-native-assets.md][bundle-native-assets] | HIGH | Asset catalog setup |
| [bundle-library-size.md][bundle-library-size] | MEDIUM | Evaluate dependencies |
| [bundle-code-splitting.md][bundle-code-splitting] | MEDIUM | Remote chunk loading safeguards |
## Problem → Skill Mapping
| Problem | Start With |
|---------|------------|
| App feels slow/janky | [js-measure-fps.md][js-measure-fps] → [js-profile-react.md][js-profile-react] |
| Too many re-renders | [js-profile-react.md][js-profile-react] → [js-react-compiler.md][js-react-compiler] |
| Slow startup (TTI) | [native-measure-tti.md][native-measure-tti] → [bundle-analyze-js.md][bundle-analyze-js] |
| Large app size | [bundle-analyze-app.md][bundle-analyze-app] → [bundle-r8-android.md][bundle-r8-android] |
| Memory growing | [js-memory-leaks.md][js-memory-leaks] or [native-memory-leaks.md][native-memory-leaks] |
| Animation drops frames | [js-animations-reanimated.md][js-animations-reanimated] |
| Bottom sheet jank/re-renders | [js-bottomsheet.md][js-bottomsheet] → [js-animations-reanimated.md][js-animations-reanimated] |
| List scroll jank | [js-lists-flatlist-flashlist.md][js-lists-flatlist-flashlist] |
| TextInput lag | [js-uncontrolled-components.md][js-uncontrolled-components] |
| Native module slow | [native-turbo-modules.md][native-turbo-modules] → [native-threading-model.md][native-threading-model] |
| Native library alignment issue | [native-android-16kb-alignment.md][native-android-16kb-alignment] |
[references]: references/
[js-lists-flatlist-flashlist]: references/js-lists-flatlist-flashlist.md
[js-profile-react]: references/js-profile-react.md
[js-measure-fps]: references/js-measure-fps.md
[js-memory-leaks]: references/js-memory-leaks.md
[js-atomic-state]: references/js-atomic-state.md
[js-concurrent-react]: references/js-concurrent-react.md
[js-react-compiler]: references/js-react-compiler.md
[js-animations-reanimated]: references/js-animations-reanimated.md
[js-bottomsheet]: references/js-bottomsheet.md
[js-uncontrolled-components]: references/js-uncontrolled-components.md
[native-turbo-modules]: references/native-turbo-modules.md
[native-sdks-over-polyfills]: references/native-sdks-over-polyfills.md
[native-measure-tti]: references/native-measure-tti.md
[native-threading-model]: references/native-threading-model.md
[native-profiling]: references/native-profiling.md
[native-platform-setup]: references/native-platform-setup.md
[native-view-flattening]: references/native-view-flattening.md
[native-memory-patterns]: references/native-memory-patterns.md
[native-memory-leaks]: references/native-memory-leaks.md
[native-android-16kb-alignment]: references/native-android-16kb-alignment.md
[bundle-barrel-exports]: references/bundle-barrel-exports.md
[bundle-analyze-js]: references/bundle-analyze-js.md
[bundle-tree-shaking]: references/bundle-tree-shaking.md
[bundle-analyze-app]: references/bundle-analyze-app.md
[bundle-r8-android]: references/bundle-r8-android.md
[bundle-hermes-mmap]: references/bundle-hermes-mmap.md
[bundle-native-assets]: references/bundle-native-assets.md
[bundle-library-size]: references/bundle-library-size.md
[bundle-code-splitting]: references/bundle-code-splitting.md
## Attribution
Based on "The Ultimate Guide to React Native Optimization" by Callstack.
Referenced files: 43
react-native-tv-best-practices10.9 KB
View saved version →
---
name: react-native-tv-best-practices
description: Reviews React Native TV apps for focus/D-pad navigation, 10-foot UI layout, TV playback/DRM integration, low-memory TV performance, and TV accessibility. Use when building, debugging, or reviewing react-native-tvos, Expo TV, Amazon Vega/Kepler, or React Native web TV targets where the issue depends on remote input, TV focus, TV packaging, TV hardware, or TV playback constraints.
license: MIT
---
# React Native TV Best Practices
## Overview
TV-specific review guidance for React Native-backed apps on Apple TV, Android TV, Fire TV, Amazon Vega/Kepler, and web-based TV targets such as Tizen or webOS.
Use this skill only for TV deltas: remote input, focus engines, 10-foot layout, platform packaging, playback/DRM, low-memory TV hardware, and TV accessibility. For ordinary React Native performance or architecture issues, use [react-native-best-practices](../react-native-best-practices/SKILL.md).
## Skill Format
Reference files are grouped by topic prefix:
- `focus-*`: focus engines, focus guides, focus event performance
- `nav-*`: D-pad navigation, Back/Menu behavior, keyboard/search input
- `design-*`: 10-foot typography, layout, color, focus visibility
- `perf-*`: startup, memory, lists, animation, and network constraints on TV hardware
- `video-*`: playback architecture, DRM/protocol selection, debugging
- `a11y-*`: TV accessibility implementation and audit checks
- `setup-*`: stack detection, setup, architecture, cross-platform behavior
- `test-*` and `release-*`: test coverage, E2E, and CI/release workflows
## When to Apply
Apply this skill when the app targets a TV platform and the work involves:
- Focus movement, visible focus, focus restoration, or remote/D-pad input
- TV layout readability, overscan/safe areas, or 10-foot UI density
- TV player controls, manifests, DRM, decoder support, or playback errors
- Performance on low-memory TV hardware, especially with video or large carousels
- TV accessibility with screen readers, captions, focus order, or remote-only interaction
- Platform setup for `react-native-tvos`, Expo TV, Amazon Vega/Kepler, Tizen, or webOS
## Before You Start — Identify the TV Stack
This skill covers several TV stacks. **Detect which one the app targets before flagging setup issues** — demanding `react-native-tvos`, a tvOS Podfile, or an Android TV manifest on a Vega/Kepler or web-based TV app produces false positives.
| Stack | How to detect | Setup expectations |
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **react-native-tvos** (Apple TV, Android TV, Fire TV) | `"react-native": "npm:react-native-tvos@…"` in package.json | tvOS Podfile (`platform :tvos`); Android TV `leanback`/`LEANBACK_LAUNCHER` manifest entries; TV emulator/simulator |
| **Expo + react-native-tvos** | above **plus** `@react-native-tvos/config-tv` in app.json | `EXPO_TV=1` prebuild; `react-native-tvos` version must match the Expo SDK; not all Expo features/libraries are available on TV |
| **Amazon Vega / Kepler** | Vega/Kepler SDK & tooling (`@amazon-devices/*` deps, Kepler manifest); **no** `react-native-tvos` | Amazon's Vega/Kepler toolchain — `react-native-tvos`, tvOS Podfile, and Android TV manifest do **not** apply |
| **Web-based TV** (Tizen, webOS) | web bundler (Rsbuild/webpack) + platform packaging; spatial-nav library | Platform SDK packaging; `@noriginmedia/norigin-spatial-navigation` for focus |
The focus, 10-foot design, performance, accessibility, and player guidance applies across all of these — only the **setup/build** expectations are stack-specific.
## Review Rules
- Resolve the target stack before setup advice.
- Prefer natural focus order and focus guides before imperative focus calls or broad `nextFocus*` maps.
- Treat focus loss, invisible focus, and broken Back/Menu behavior as navigation bugs.
- Check readability, safe areas, and focus states at TV distance before tuning visual details.
- Profile on the weakest supported TV device before reporting performance fixes as complete.
- Separate playback failures by layer: manifest request, DRM license exchange, decoder capability, player state, and React UI controls.
## Priority-Ordered Guidelines
| Priority | Category | Impact | Prefix |
|----------|----------|--------|--------|
| 1 | Focus and D-pad navigation | CRITICAL | `focus-*`, `nav-*` |
| 2 | List, animation, and input performance | CRITICAL | `perf-*` |
| 3 | Playback and DRM failures | HIGH | `video-*` |
| 4 | 10-foot readability and layout | HIGH | `design-*` |
| 5 | TV accessibility | HIGH | `a11y-*` |
| 6 | Stack setup, testing, and release | MEDIUM | `setup-*`, `test-*`, `release-*` |
## Quick Reference
1. Detect the TV stack from package files, manifests, native folders, and platform tooling.
2. Reproduce navigation with the remote or D-pad path, not mouse/touch assumptions.
3. Confirm the focused element is always visible, reachable, and restored after modals/routes.
4. Check playback failures from the network/DRM layer upward before changing React controls.
5. Measure list, animation, memory, and startup work on the weakest supported TV target.
## References
### Focus and Navigation
| File | Impact | Description |
|------|--------|-------------|
| [focus-management.md](references/focus-management.md) | CRITICAL | Focus engines, focus guides, `nextFocus*`, and focus restoration |
| [focus-performance.md](references/focus-performance.md) | CRITICAL | Avoiding frame drops from focus event handling |
| [nav-directional.md](references/nav-directional.md) | CRITICAL | Directional navigation rules across TV platforms |
| [nav-patterns.md](references/nav-patterns.md) | CRITICAL | Global/local navigation, modals, tabs, and Back behavior |
| [nav-keyboard.md](references/nav-keyboard.md) | MEDIUM | Search and text input with remotes |
### Design
| File | Impact | Description |
|------|--------|-------------|
| [design-10foot.md](references/design-10foot.md) | HIGH | 10-foot review heuristics |
| [design-typography.md](references/design-typography.md) | HIGH | TV type sizing and readability |
| [design-layout.md](references/design-layout.md) | HIGH | Safe areas, spacing, carousels, and focus room |
| [design-color.md](references/design-color.md) | MEDIUM | Contrast and TV display color constraints |
### Performance
| File | Impact | Description |
|------|--------|-------------|
| [perf-overview.md](references/perf-overview.md) | HIGH | TV performance targets and profiling order |
| [perf-lists.md](references/perf-lists.md) | CRITICAL | Virtualized rows and poster-heavy lists |
| [perf-animations.md](references/perf-animations.md) | CRITICAL | Focus and transition animation performance |
| [perf-memory.md](references/perf-memory.md) | HIGH | Low-memory TV crashes and image/video pressure |
| [perf-network.md](references/perf-network.md) | HIGH | Remote input, request stalls, and network resilience |
### Video, Accessibility, Setup, Testing
| File | Impact | Description |
|------|--------|-------------|
| [video-streaming.md](references/video-streaming.md) | HIGH | TV platform protocol/DRM selection |
| [video-players.md](references/video-players.md) | HIGH | Player choices and custom controls |
| [video-debugging.md](references/video-debugging.md) | HIGH | Manifest, DRM, codec, and playback debugging |
| [a11y-overview.md](references/a11y-overview.md) | MEDIUM | TV-specific accessibility differences |
| [a11y-implementation.md](references/a11y-implementation.md) | HIGH | Accessible labels, roles, live regions, and focus |
| [a11y-checklist.md](references/a11y-checklist.md) | MEDIUM | Launch accessibility audit checklist |
| [setup-getting-started.md](references/setup-getting-started.md) | MEDIUM | `react-native-tvos` and Expo TV setup |
| [setup-cross-platform.md](references/setup-cross-platform.md) | MEDIUM | Platform detection and cross-platform caveats |
| [setup-architecture.md](references/setup-architecture.md) | MEDIUM | Code sharing and project structure |
| [test-strategy.md](references/test-strategy.md) | MEDIUM | TV testing scope and coverage split |
| [test-javascript.md](references/test-javascript.md) | MEDIUM | JS-level remote/focus test helpers |
| [test-e2e.md](references/test-e2e.md) | MEDIUM | Appium and TV E2E coverage |
| [release-cicd.md](references/release-cicd.md) | MEDIUM | CI, build fingerprinting, and release checks |
## Problem → Skill Mapping
| Symptom | Start Here |
| ------------------------------------ | ---------------------------------------------------------------------------- |
| "Focus jumps to wrong element" | [focus-management.md](references/focus-management.md) → Debugging section |
| "App freezes when scrolling lists" | [perf-lists.md](references/perf-lists.md) → Virtualization |
| "Animations stutter on Fire TV" | [perf-animations.md](references/perf-animations.md) → Native driver |
| "Text too small on TV" | [design-typography.md](references/design-typography.md) → Minimum sizes |
| "Video won't play / DRM errors" | [video-streaming.md](references/video-streaming.md) → DRM section |
| "Screen reader skips elements" | [a11y-implementation.md](references/a11y-implementation.md) → Roles & labels |
| "Back button doesn't work right" | [nav-patterns.md](references/nav-patterns.md) → Back navigation |
| "Keyboard covers content" | [nav-keyboard.md](references/nav-keyboard.md) → Built-in vs custom |
| "App takes forever to start" | [perf-overview.md](references/perf-overview.md) → Startup time |
| "Images causing memory crashes" | [perf-memory.md](references/perf-memory.md) → Image optimization |
| "CI pipeline takes hours" | [release-cicd.md](references/release-cicd.md) → Fingerprinting |
| "How to share code across platforms" | [setup-architecture.md](references/setup-architecture.md) → Code sharing |
## Security (TV-Specific)
General dependency/input hygiene applies as in any RN app; the TV-specific deltas worth calling out:
- Never embed FairPlay/Widevine/PlayReady keys in client code — treat the license server as the trust boundary and keep DRM tokens server-issued.
Referenced files: 28