---
description: Mobile Performance
alwaysApply: false
---

# Mobile Performance

Optimizing mobile app performance for smooth user experience.

## Performance Goals

60 FPS animations, < 3s cold start, < 100ms touch feedback, minimal battery drain.

## List Performance

```tsx
<FlatList
  data={items}
  renderItem={renderItem}
  keyExtractor={keyExtractor}
  removeClippedSubviews={true}
  maxToRenderPerBatch={10}
  windowSize={5}
  getItemLayout={(_, index) => ({
    length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index,
  })}
/>
```

- Memoize list items with `memo`, callbacks with `useCallback`, extractors outside render

## Rendering Optimization

```tsx
// Bad: inline objects/functions cause re-renders
<View style={{ padding: 10 }}>
<Button onPress={() => handlePress(id)} />

// Good: StyleSheet.create + useCallback
const styles = StyleSheet.create({ container: { padding: 10 } });
const onPress = useCallback(() => handlePress(id), [id]);
```

- Use `useMemo` for expensive computed values
- Debounce search input and other rapid-fire operations (300ms typical)

## Images

- Specify dimensions; request server-side resized images; use `FastImage` with immutable cache
- Lazy load via `FlatList` `windowSize`

## Animations

- Use `useNativeDriver: true` for `Animated` (supports `transform`, `opacity` only)
- Use Reanimated for complex gesture-driven animations (`useSharedValue`, `useAnimatedStyle`)

## Startup Performance

- Defer non-critical work with `InteractionManager.runAfterInteractions`
- Lazy-load secondary screens with `React.lazy` + `Suspense`

## Memory Management

```tsx
useEffect(() => {
  const sub = eventEmitter.addListener('event', handler);
  return () => sub.remove(); // always cleanup
}, []);
```

- Guard async `setState` with mounted check or AbortController
- Monitor heap with `HermesInternal.getRuntimeProperties()` in dev

## Anti-Patterns

- **JS thread blocking** — move heavy computation to `InteractionManager` or worker
- **Unbatched animations** — use `Animated.parallel` instead of individual starts in a loop
- **Inline styles/callbacks** — causes unnecessary re-renders every frame
