| name | performance |
| description | Review React Native code for rendering performance, list virtualisation, memoisation, image handling, animations, and memory/resource cleanup. Use when a screen feels janky, before merging UI-heavy code, or when profiling. |
| version | 1.0.1 |
| platforms | ["ios","android"] |
| react-native-version | 0.76+ |
| tags | ["react-native","performance","memory","rendering"] |
Performance Skill
Applicability
- Platforms: iOS and Android
- React Native: 0.76+ (New Architecture interop assumed unless a checklist item says otherwise)
When to Use
- A screen drops frames, stutters, or feels slow
- Reviewing UI-heavy code or long lists before merge
- Profiling re-renders or memory growth over a session
- Adding animations or large images
Guidance
Rendering
Incorrect:
<UserCard onPress={() => handlePress(user.id)} />
Correct:
const handleUserPress = useCallback((id: string) => {
handlePress(id);
}, [handlePress]);
<UserCard onPress={handleUserPress} userId={user.id} />
Lists
Images
Animations
Loading & Imports
Memory & Resources
Incorrect:
useEffect(() => {
const interval = setInterval(pollStatus, 5000);
}, []);
Correct:
useEffect(() => {
const interval = setInterval(pollStatus, 5000);
return () => clearInterval(interval);
}, []);
Anti-Patterns
| Anti-Pattern | Risk | Fix |
|---|
FlatList for long lists | Frame drops | Use FlashList or equivalent |
| Frequent reads from slow storage | Blocks JS thread | Use a fast key-value store (e.g. MMKV) |
Animated API for complex animations | JS-thread jank | Use Reanimated |
| Inline styles in render | New object each render, breaks memo | StyleSheet.create |
| Over-memoising trivial components | Adds overhead with no benefit | Measure first, memoise hotspots |
Pitfalls
- Over-memoising simple components costs more than it saves — measure before optimising.
useMemo or useCallback with the wrong dependency array silently returns stale values.
- Memory leaks compound over a long session (users keep apps open for hours), so cleanup matters even for short-lived screens.
- An
AbortController must be created per request, not shared across calls.