Performance optimization of Expo apps is key to ensuring a good user experience. Expo is based on React Native, so many React Native performance optimization techniques apply equally, while Expo also provides some specific optimization tools and strategies.
Performance Optimization Strategies:
- Component Rendering Optimization
Use React.memo, useMemo, and useCallback to reduce unnecessary renders:
typescript// Use React.memo to avoid unnecessary re-renders const MyComponent = React.memo(({ data }) => { return <Text>{data.value}</Text>; }); // Use useMemo to cache computation results function ExpensiveComponent({ items }) { const sortedItems = useMemo(() => { return items.sort((a, b) => a.id - b.id); }, [items]); return <FlatList data={sortedItems} />; } // Use useCallback to cache functions function ParentComponent() { const handleClick = useCallback(() => { console.log('Clicked'); }, []); return <ChildComponent onClick={handleClick} />; }
- List Optimization
Use FlatList instead of ScrollView for long lists:
typescript<FlatList data={items} renderItem={({ item }) => <Item item={item} />} keyExtractor={(item) => item.id} removeClippedSubviews={true} maxToRenderPerBatch={10} windowSize={10} initialNumToRender={10} getItemLayout={(data, index) => ({ length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index, })} />
Key Properties Explained:
removeClippedSubviews: Remove off-screen viewsmaxToRenderPerBatch: Number of items to render per batchwindowSize: Rendering window sizeinitialNumToRender: Initial number of items to rendergetItemLayout: Provide item layout information
- Image Optimization
Use expo-image and image caching strategies:
typescriptimport { Image } from 'expo-image'; <Image source={{ uri: 'https://example.com/image.jpg' }} style={{ width: 200, height: 200 }} cachePolicy="memory-disk" contentFit="cover" transition={200} />
Optimization Tips:
- Use appropriate image sizes
- Enable caching strategies
- Use WebP format
- Lazy load images
- Network Request Optimization
Use caching and request deduplication:
typescriptimport { useQuery } from '@tanstack/react-query'; function UserProfile({ userId }) { const { data, isLoading } = useQuery({ queryKey: ['user', userId], queryFn: () => fetchUser(userId), staleTime: 5 * 60 * 1000, // 5 minutes cacheTime: 10 * 60 * 1000, // 10 minutes }); if (isLoading) return <Loading />; return <Text>{data.name}</Text>; }
- Animation Optimization
Use react-native-reanimated for high-performance animations:
typescriptimport Animated, { useSharedValue, useAnimatedStyle, withTiming, } from 'react-native-reanimated'; function AnimatedBox() { const opacity = useSharedValue(0); const animatedStyle = useAnimatedStyle(() => { return { opacity: withTiming(opacity.value, { duration: 500 }), }; }); useEffect(() => { opacity.value = 1; }, []); return <Animated.View style={animatedStyle} />; }
- Memory Management
Release resources promptly:
typescript// Cancel network requests useEffect(() => { const controller = new AbortController(); fetchData(controller.signal); return () => controller.abort(); }, []); // Clean up timers useEffect(() => { const timer = setInterval(() => { console.log('Tick'); }, 1000); return () => clearInterval(timer); }, []); // Clean up subscriptions useEffect(() => { const subscription = someEvent.subscribe(); return () => subscription.unsubscribe(); }, []);
- Bundle Optimization
Reduce app bundle size:
typescript// Code splitting const LazyComponent = React.lazy(() => import('./LazyComponent')); // Dynamic imports const loadModule = async () => { const module = await import('./heavyModule'); module.doSomething(); }; // Remove unused dependencies npm prune
- Use Expo Performance Tools
Expo provides some performance monitoring tools:
typescriptimport { Performance } from 'react-native'; // Record performance marks Performance.mark('component-start'); // After component renders Performance.mark('component-end'); // Measure performance Performance.measure('component-render', 'component-start', 'component-end');
Performance Analysis Tools:
-
React DevTools Profiler
- Analyze component rendering performance
- Identify performance bottlenecks
- Optimize render counts
-
Flipper
- Network request monitoring
- Layout inspection
- Memory analysis
-
Expo DevTools
- Real-time performance monitoring
- Bundle size analysis
- Load time tracking
Common Performance Issues and Solutions:
-
List Scrolling Lag
- Use FlatList instead of ScrollView
- Enable
removeClippedSubviews - Provide correct
getItemLayout
-
Slow Image Loading
- Use expo-image
- Enable caching
- Use appropriate image sizes
-
Slow App Startup
- Optimize initialization code
- Lazy load non-critical modules
- Use splash screens
-
Memory Leaks
- Clean up subscriptions and timers promptly
- Use WeakMap and WeakSet
- Regularly check memory usage
Best Practices:
-
Performance Monitoring: Regularly analyze apps with performance tools
-
Progressive Optimization: Optimize critical paths first, then secondary features
-
Test Coverage: Test performance on different devices
-
Continuous Optimization: Make performance optimization a continuous process
-
User Experience: Balance performance and functionality, prioritize core experience
Through systematic performance optimization, you can significantly improve the user experience and competitiveness of Expo apps.