I’ve built enough React Native apps to know where they usually fall apart: startup time, list scrolling, and animations. These are the settings and patterns I now apply by default.
Performance Optimization
1. Use Hermes Engine
Hermes significantly improves startup time and memory usage:
project.ext.react = [ enableHermes: true]2. Implement Lazy Loading
const HomeScreen = lazy(() => import('./screens/HomeScreen'));
function App() { return ( <Suspense fallback={<LoadingScreen />}> <HomeScreen /> </Suspense> );}3. Optimize Images
Use proper image formats and implement caching:
import FastImage from 'react-native-fast-image';
<FastImage style={styles.image} source={{ uri: imageUrl, priority: FastImage.priority.normal, }} resizeMode={FastImage.resizeMode.cover}/>State Management
Redux Toolkit
import { configureStore, createSlice } from '@reduxjs/toolkit';
const userSlice = createSlice({ name: 'user', initialState: { profile: null }, reducers: { setProfile: (state, action) => { state.profile = action.payload; } }});
export const store = configureStore({ reducer: { user: userSlice.reducer }});Navigation
React Navigation 6
import { NavigationContainer } from '@react-navigation/native';import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
function App() { return ( <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Home" component={HomeScreen} options={{ headerLargeTitle: true, headerTransparent: true }} /> </Stack.Navigator> </NavigationContainer> );}Animations
Reanimated 3
import Animated, { useAnimatedStyle, useSharedValue, withSpring} from 'react-native-reanimated';
function AnimatedCard() { const scale = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => ({ transform: [{ scale: scale.value }] }));
const handlePress = () => { scale.value = withSpring(0.9, {}, () => { scale.value = withSpring(1); }); };
return ( <Animated.View style={[styles.card, animatedStyle]}> <TouchableOpacity onPress={handlePress}> <Text>Press me!</Text> </TouchableOpacity> </Animated.View> );}General rules
- Use TypeScript: Catch errors early and improve maintainability
- Implement Error Boundaries: Gracefully handle crashes
- Optimize Bundle Size: Use dynamic imports and tree shaking
- Test on Real Devices: Simulators don’t catch all issues
- Monitor Performance: Use Flipper and React DevTools
Conclusion
Most React Native jank traces back to skipping one of the items above. Profile on a real low-end device before deciding the app is fast.