Documentation Index
Fetch the complete documentation index at: https://mintlify.com/facebook/react-native/llms.txt
Use this file to discover all available pages before exploring further.
Performance Overview
Learn how to build high-performance React Native applications by understanding optimization techniques, performance bottlenecks, and best practices.
React Native apps run on three main threads:
- JavaScript Thread: Executes your JavaScript code and React logic
- Main/UI Thread: Handles UI rendering and user interactions
- Native Modules Thread: Processes native module calls
Performance issues typically occur when these threads are blocked or communication between them is inefficient.
JavaScript Engine
React Native supports multiple JavaScript engines:
Hermes Engine (Recommended)
Hermes is optimized for React Native:
// Android - android/app/build.gradle
project.ext.react = [
enableHermes: true
]
# iOS - Podfile
use_react_native!(
:path => config[:reactNativePath],
:hermes_enabled => true
)
Hermes Benefits:
- Faster app startup time
- Reduced memory usage
- Smaller app size
- Optimized bytecode compilation
JavaScriptCore (JSC)
Default engine on iOS, optional on Android:
enableHermes: false // Use JSC instead
Key metrics to monitor:
Frame Rate
Target 60 FPS (16.67ms per frame) for smooth animations:
import { PerformanceObserver } from 'react-native';
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log(`${entry.name}: ${entry.duration}ms`);
});
});
observer.observe({ entryTypes: ['measure'] });
import { InteractionManager } from 'react-native';
InteractionManager.runAfterInteractions(() => {
// Expensive operation after animations complete
processLargeDataset();
});
Memory Usage
Monitor memory allocation and garbage collection:
if (__DEV__) {
const { performance } = require('react-native');
console.log('Memory:', performance.memory);
}
1. Unnecessary Re-renders
Use React.memo and useMemo to prevent re-renders:
import React, { memo, useMemo } from 'react';
const ExpensiveComponent = memo(({ data }) => {
const processedData = useMemo(
() => expensiveOperation(data),
[data]
);
return <View>{processedData}</View>;
});
2. Bridge Overhead
Minimize JavaScript-to-native communication:
// Bad: Multiple bridge calls
for (let i = 0; i < 100; i++) {
NativeModule.updateValue(i);
}
// Good: Batch operations
NativeModule.updateValues(Array.from({ length: 100 }, (_, i) => i));
3. Large Lists
Use FlatList or SectionList with proper optimizations:
import { FlatList } from 'react-native';
const OptimizedList = () => (
<FlatList
data={largeDataset}
renderItem={renderItem}
keyExtractor={item => item.id}
getItemLayout={(data, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
})}
initialNumToRender={10}
maxToRenderPerBatch={10}
windowSize={5}
removeClippedSubviews={true}
/>
);
See Optimizing FlatList for details.
4. Heavy Computations
Move heavy computations off the main thread:
import { useEffect, useState } from 'react';
const HeavyComputation = ({ data }) => {
const [result, setResult] = useState(null);
useEffect(() => {
// Use Web Worker or native module
const worker = new Worker('./computation.worker.js');
worker.postMessage(data);
worker.onmessage = (e) => setResult(e.data);
return () => worker.terminate();
}, [data]);
return <Text>{result}</Text>;
};
Optimization Techniques
Use Native Driver for Animations
import { Animated } from 'react-native';
const fadeAnim = new Animated.Value(0);
Animated.timing(fadeAnim, {
toValue: 1,
duration: 1000,
useNativeDriver: true, // Run on native thread
}).start();
Optimize Images
import { Image } from 'react-native';
import FastImage from 'react-native-fast-image';
// Use appropriate image formats and sizes
<Image
source={{ uri: 'https://example.com/image.jpg' }}
style={{ width: 200, height: 200 }}
resizeMode="cover"
/>
// Consider FastImage for better performance
<FastImage
source={{
uri: 'https://example.com/image.jpg',
priority: FastImage.priority.normal,
}}
style={{ width: 200, height: 200 }}
resizeMode={FastImage.resizeMode.contain}
/>
Lazy Loading
import React, { lazy, Suspense } from 'react';
const HeavyComponent = lazy(() => import('./HeavyComponent'));
const App = () => (
<Suspense fallback={<LoadingSpinner />}>
<HeavyComponent />
</Suspense>
);
Code Splitting
Use inline requires for better startup time:
// Load module only when needed
const handlePress = () => {
const HeavyModule = require('./HeavyModule').default;
HeavyModule.doSomething();
};
See RAM Bundles and Inline Requires for details.
Development vs Production
Development Mode
Development builds include:
- Additional warnings and checks
- Source maps for debugging
- Hot reloading overhead
- Unoptimized code
Production Mode
Production builds are optimized:
# Android
cd android
./gradlew assembleRelease
# iOS
xcodebuild -workspace ios/App.xcworkspace \
-scheme App \
-configuration Release
Production optimizations:
- Minified JavaScript
- Removed PropTypes checks
- Disabled dev warnings
- Optimized native code
- Bytecode precompilation (Hermes)
import { Profiler } from 'react';
const onRenderCallback = (id, phase, actualDuration) => {
console.log(`${id} (${phase}) took ${actualDuration}ms`);
};
<Profiler id="MyComponent" onRender={onRenderCallback}>
<MyComponent />
</Profiler>
import { performance } from 'react-native';
performance.mark('operation-start');
// ... expensive operation
performance.mark('operation-end');
performance.measure(
'operation',
'operation-start',
'operation-end'
);
const measure = performance.getEntriesByName('operation')[0];
console.log(`Operation took ${measure.duration}ms`);
Android:
- Android Profiler in Android Studio
- Systrace
- Method tracing
iOS:
- Instruments (Time Profiler, Allocations)
- Xcode Debug Navigator
- Metal System Trace
Android
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
iOS
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ONLY_ACTIVE_ARCH'] = 'NO'
config.build_settings['GCC_OPTIMIZATION_LEVEL'] = 's'
end
end
end
Next Steps