Everything-react-native-expo performance-optimization
Step-by-step performance diagnosis and optimization for React Native apps
install
source · Clone the upstream repo
git clone https://github.com/JubaKitiashvili/everything-react-native-expo
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/JubaKitiashvili/everything-react-native-expo "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/performance-optimization" ~/.claude/skills/jubakitiashvili-everything-react-native-expo-performance-optimization && rm -rf "$T"
manifest:
.claude/skills/performance-optimization/SKILL.mdsource content
Performance Optimization
You are performing a systematic performance diagnosis on a React Native application. Follow this step-by-step process.
When to Use This Skill
Invoke when:
- App feels slow or janky
- Startup time is too long
- Lists scroll poorly
- Animations stutter
- Bundle size is too large
- Memory usage is high
Diagnostic Process
Step 1: Identify the Problem
| Symptom | Likely Cause | First Check |
|---|---|---|
| Slow startup | Large bundle, heavy init | Bundle size, eager imports |
| Janky scrolling | List renderer, heavy cells | FlatList vs FlashList, cell complexity |
| Stuttering animations | JS thread blocking | Worklets, |
| High memory | Leaks, large images | Image caching, subscription cleanup |
| Slow navigation | Heavy screens, eager loading | Lazy loading, screen weight |
Step 2: Measure
Bundle Analysis:
npx react-native-bundle-visualizer # or for Expo: npx expo export --dump-sourcemap
Target: < 1.5MB JavaScript bundle
FPS Monitoring:
- Enable Perf Monitor in dev menu
- Or use
from ReanimateduseFrameCallback - Target: 60fps constant, no drops below 55fps
TTI (Time to Interactive):
- Measure from app launch to first interactive frame
- Target: < 2 seconds on mid-range device
Memory:
- Use Xcode Instruments (iOS) or Android Profiler
- Watch for monotonically increasing memory (leak indicator)
Step 3: Optimize by Category
Bundle Size:
- Analyze imports — find large dependencies
- Lazy load screens:
withReact.lazy()Suspense - Tree-shake unused exports
- Replace large libraries with lighter alternatives
- Use Hermes (enabled by default in Expo SDK 50+)
Rendering:
- Replace
withFlatList
+FlashListestimatedItemSize - Memoize expensive components:
React.memo - Use
for event handlers passed to childrenuseCallback - Avoid inline object/array creation in JSX
- Profile re-renders with React DevTools Profiler
Animations:
- Move all animations to UI thread (Reanimated worklets)
- Use
instead of inline animated valuesuseAnimatedStyle - Batch related animations with
/withSequencewithDelay - Reduce animated property count (transform is cheaper than layout)
- Use
for cleanupcancelAnimation
Images:
- Use
withexpo-imagecachePolicy="memory-disk" - Serve correct sizes (don't scale 4K images to thumbnails)
- Use WebP format for smaller file sizes
- Implement progressive loading (blurhash placeholder)
Memory:
- Clean up listeners in
returnuseEffect - Remove event subscriptions on unmount
- Use WeakRef for caches where appropriate
- Paginate large data sets (don't load all at once)
Step 4: Verify Improvements
Re-measure after each optimization:
## Performance Report | Metric | Before | After | Target | Status | |--------|--------|-------|--------|--------| | Bundle size | 2.1MB | 1.4MB | <1.5MB | PASS | | TTI | 3.2s | 1.8s | <2s | PASS | | List FPS | 45fps | 60fps | 60fps | PASS | | Memory (5min) | +80MB | +12MB | <20MB | PASS |