Performance optimization is crucial for a smooth user experience in React Native apps. Here are the best techniques:
useMemo
and useCallback
to Prevent Unnecessary RendersReact components re-render when props or state change. Use useMemo
and useCallback
to optimize performance.
useMemo
: Caches expensive calculations.useCallback
: Caches function instances.import React, { useState, useMemo, useCallback } from 'react';
import { View, Text, Button } from 'react-native';
const ExpensiveComponent = ({ count }) => {
const computedValue = useMemo(() => {
console.log('Recalculating...');
return count * 2;
}, [count]);
return <Text>Computed Value: {computedValue}</Text>;
};
const App = () => {
const [count, setCount] = useState(0);
const increment = useCallback(() => setCount(count + 1), [count]);
return (
<View>
<ExpensiveComponent count={count} />
<Button title="Increment" onPress={increment} />
</View>
);
};
export default App;
* Reduces re-renders, improving performance.
React.memo
to Avoid Re-Rendering Unchanged ComponentsReact re-renders child components even if their props haven’t changed. Use React.memo
to prevent this.
import React, { useState } from 'react';
import { View, Text, Button } from 'react-native';
const MemoizedText = React.memo(({ text }) => {
console.log('Rendering MemoizedText');
return <Text>{text}</Text>;
});
const App = () => {
const [count, setCount] = useState(0);
return (
<View>
<MemoizedText text="This component won't re-render" />
<Text>Count: {count}</Text>
<Button title="Increment" onPress={() => setCount(count + 1)} />
</View>
);
};
export default App;
* Prevents unnecessary re-renders of static components.
When dealing with large lists, avoid using ScrollView
. Instead, use FlatList
, which efficiently renders only the visible items.
<ScrollView>
{data.map(item => (
<Text key={item.id}>{item.name}</Text>
))}
</ScrollView>
* ScrollView
loads all items into memory at once, causing slowdowns.
<FlatList
data={data}
keyExtractor={item => item.id}
renderItem={({ item }) => <Text>{item.name}</Text>}
initialNumToRender={10} // Render only 10 items initially
maxToRenderPerBatch={10} // Load items in batches
windowSize={5} // Keep only 5 screens worth of items in memory
/>
* FlatList only renders visible items, improving performance.
react-native-fast-image
)Large, unoptimized images can slow down your app.
react-native-fast-image
Install it:
npm install react-native-fast-image
Usage:
import FastImage from 'react-native-fast-image';
<FastImage
style={{ width: 200, height: 200 }}
source={{ uri: 'https://example.com/image.jpg' }}
resizeMode={FastImage.resizeMode.cover}
/>
InteractionManager
for Heavy TasksTo avoid blocking UI updates, defer heavy tasks using InteractionManager
.
import { InteractionManager } from 'react-native';
useEffect(() => {
const task = InteractionManager.runAfterInteractions(() => {
// Perform expensive operations here
});
return () => task.cancel();
}, []);
* Ensures animations and UI remain smooth.
setState
CallsEvery time you update state, React re-renders the component. Minimize unnecessary state updates.
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
setCount(count + 2);
};
* Causes multiple re-renders.
const increment = () => {
setCount(prev => prev + 2);
};
Hermes is a lightweight JavaScript engine optimized for React Native.
Edit android/app/build.gradle
:
enableHermes: true
Then rebuild the project:
cd android && ./gradlew clean
cd .. && npx react-native run-android
* Improves startup time and reduces memory usage.
react-native-reanimated
)Use react-native-reanimated
for smoother animations instead of Animated
.
react-native-reanimated
npm install react-native-reanimated
import Animated, { Easing } from 'react-native-reanimated';
const animation = new Animated.Value(0);
Animated.timing(animation, {
toValue: 1,
duration: 500,
easing: Easing.linear,
}).start();
redux-persist
If you use Redux, persist the state to avoid unnecessary API calls.
redux-persist
npm install redux-persist
import { persistStore, persistReducer } from 'redux-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';
const persistConfig = { key: 'root', storage: AsyncStorage };
const persistedReducer = persistReducer(persistConfig, rootReducer);
* Reduces redundant API calls by caching state.
useNativeDriver
for AnimationsAnimations in React Native should offload work to the GPU.
Animated.timing(animatedValue, {
toValue: 1,
duration: 500,
useNativeDriver: true,
}).start();
* Prevents UI thread lag.
Optimization Tip | Benefit |
---|---|
useMemo & useCallback |
Prevents unnecessary re-renders |
React.memo |
Caches components |
Use FlatList instead of ScrollView |
Improves list performance |
Use react-native-fast-image |
Faster image loading |
Use InteractionManager |
Defer heavy tasks |
Minimize setState calls |
Reduces unnecessary re-renders |
Enable Hermes (Android) | Speeds up execution |
Use react-native-reanimated |
Improves animation smoothness |
Persist Redux state | Avoids redundant API calls |
Use useNativeDriver |
Runs animations on the GPU |