t1k:rn:performance:optimization
| Field | Value |
|---|---|
| Module | performance |
| Version | 1.6.3 |
| Effort | medium |
| Tools | — |
Keywords: bundle, FlashList, hermes, memo, optimization, performance, react native
How to invoke
Section titled “How to invoke”/t1k:rn:performance:optimizationRN Performance Optimization
Section titled “RN Performance Optimization”Hermes Engine
Section titled “Hermes Engine”// app.json — Hermes is default in Expo SDK 48+{ "expo": { "jsEngine": "hermes" }}Hermes benefits: AOT bytecode compilation, lower memory, faster startup. Never disable without profiling evidence.
FlashList (Replace FlatList for large lists)
Section titled “FlashList (Replace FlatList for large lists)”import { FlashList } from '@shopify/flash-list';
<FlashList data={items} estimatedItemSize={72} // Required — measure once, set accurately renderItem={({ item }) => <Row item={item} />} keyExtractor={(item) => item.id} drawDistance={200} // px beyond viewport to pre-render/>Memo Strategy
Section titled “Memo Strategy”// 1. memo() for expensive componentsconst Row = memo(({ item }: { item: Item }) => <View>...</View>);
// 2. useMemo for derived dataconst sorted = useMemo(() => [...items].sort(compareFn), [items]);
// 3. useCallback for stable handlersconst onPress = useCallback((id: string) => handlePress(id), [handlePress]);
// 4. Custom comparator when neededconst Row = memo(Component, (prev, next) => prev.item.id === next.item.id);Bundle Analysis
Section titled “Bundle Analysis”# Generate bundle statsnpx expo export --platform ios --dump-sourcemapnpx react-native-bundle-visualizer
# Check bundle sizenpx expo export --platform androidls -lh dist/JS Thread vs UI Thread
Section titled “JS Thread vs UI Thread”- Heavy computation →
InteractionManager.runAfterInteractions() - CPU-intensive work → offload to
react-native-workersor native module - Never block JS thread with synchronous loops during animations
Key Rules
Section titled “Key Rules”estimatedItemSizein FlashList must be accurate — measure real items, not estimate- Avoid anonymous functions in
renderItem— they create new references every render - Use
React.lazy+Suspensefor code splitting heavy screens - Profile with Flipper → Performance Monitor before optimizing — measure first
Gotchas
Section titled “Gotchas”FlatListremoveClippedSubviewscan cause blank cells on Android — test before shippingmemo()has cost — only apply to components that actually re-render unnecessarily- Hermes does not support all ES2020+ features — check compatibility before using
- FlashList requires
estimatedItemSize— missing it causes warning and poor performance