Loading...
Loading...
React Native and Expo patterns for building performant mobile apps. Covers list performance, animations with Reanimated, navigation, UI patterns, state management, platform-specific code, and Expo workflows. Use when building or reviewing React Native code. Triggers: 'react native', 'expo', 'mobile app', 'react native performance', 'flatlist', 'reanimated', 'expo router', 'mobile development', 'ios app', 'android app'.
npx skill4agent add jezweb/claude-skills react-native| Pattern | Problem | Fix |
|---|---|---|
| ScrollView for data | | Use |
| Missing keyExtractor | FlatList without | |
| Complex renderItem | Expensive component in renderItem re-renders on every scroll | Wrap in |
| Inline functions in renderItem | | Extract handler: |
| No getItemLayout | FlatList measures every item on scroll (expensive) | Provide |
| FlashList | FlatList is good, FlashList is better for large lists | |
| Large images in lists | Full-res images decoded on main thread | Use |
<FlatList
data={items}
keyExtractor={(item) => item.id}
renderItem={renderItem} // Memoised component
getItemLayout={getItemLayout} // If items are fixed height
initialNumToRender={10} // Don't render 100 items on mount
maxToRenderPerBatch={10} // Batch size for off-screen rendering
windowSize={5} // How many screens to keep in memory
removeClippedSubviews={true} // Unmount off-screen items (Android)
/>| Pattern | Problem | Fix |
|---|---|---|
| Animated API for complex animations | | Use |
| Layout animation | Item appears/disappears with no transition | |
| Shared element transitions | Navigate between screens, element teleports | |
| Gesture + animation | Drag/swipe feels laggy | |
| Measuring layout | | Use |
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated';
function AnimatedBox() {
const offset = useSharedValue(0);
const style = useAnimatedStyle(() => ({
transform: [{ translateX: withSpring(offset.value) }],
}));
return (
<GestureDetector gesture={panGesture}>
<Animated.View style={[styles.box, style]} />
</GestureDetector>
);
}| Pattern | Problem | Fix |
|---|---|---|
| Expo Router | File-based routing (like Next.js) for React Native | |
| Heavy screens on stack | Every screen stays mounted in the stack | Use |
| Deep linking | App doesn't respond to URLs | Expo Router handles this automatically. For bare RN: |
| Tab badge updates | Badge count doesn't update when tab is focused | Use |
| Navigation state persistence | App loses position on background/kill | |
app/
├── _layout.tsx # Root layout (tab navigator)
├── index.tsx # Home tab
├── (tabs)/
│ ├── _layout.tsx # Tab bar config
│ ├── home.tsx
│ ├── search.tsx
│ └── profile.tsx
├── [id].tsx # Dynamic route
└── modal.tsx # Modal route| Pattern | Problem | Fix |
|---|---|---|
| Safe area | Content under notch or home indicator | |
| Keyboard avoidance | Form fields hidden behind keyboard | |
| Platform-specific code | iOS and Android need different behaviour | |
| Status bar | Status bar overlaps content or wrong colour | |
| Touch targets | Buttons too small to tap | Minimum 44x44pt. Use |
| Haptic feedback | Taps feel dead | |
| Pattern | Problem | Fix |
|---|---|---|
| Image component | | Use |
| Remote images without dimensions | Layout shift when image loads | Always specify |
| Large images | OOM crashes on Android | Resize server-side or use |
| SVG | SVG support isn't native | |
| Video | Video playback | |
| Pattern | Problem | Fix |
|---|---|---|
| AsyncStorage for complex data | JSON parse/stringify on every read | Use MMKV ( |
| Global state | Redux/MobX boilerplate for simple state | Zustand — minimal, works great with React Native |
| Server state | Manual fetch + loading + error + cache | TanStack Query — same as web, works in React Native |
| Offline first | App unusable without network | TanStack Query |
| Deep state updates | Spread operator hell for nested objects | Immer via Zustand: |
| Pattern | When | How |
|---|---|---|
| Development build | Need native modules | |
| Expo Go | Quick prototyping, no native modules | |
| EAS Build | CI/CD, app store builds | |
| EAS Update | Hot fix without app store review | |
| Config plugins | Modify native config without ejecting | |
| Environment variables | Different configs per build | |
npx create-expo-app my-app --template tabs
cd my-app
npx expo install expo-image react-native-reanimated react-native-gesture-handler react-native-safe-area-context| Tool | For | Setup |
|---|---|---|
| Jest | Unit tests, hook tests | Included with Expo by default |
| React Native Testing Library | Component tests | |
| Detox | E2E tests on real devices/simulators | |
| Maestro | E2E with YAML flows | |
| Gotcha | Fix |
|---|---|
| Metro bundler cache | |
| Pod install issues (iOS) | |
| Reanimated not working | Must be first import: |
| Expo SDK upgrade | |
| Android build fails | Check |
| iOS simulator slow | Use physical device for performance testing — simulator doesn't reflect real perf |