React Native Performance Optimization
Master advanced techniques to build lightning-fast React Native applications. This comprehensive guide covers everything from bundle optimization to memory management.
What You'll Learn
- ✅ Identify and fix performance bottlenecks
- ✅ Optimize bundle size and startup time
- ✅ Implement efficient memory management
- ✅ Master rendering optimization techniques
- ✅ Use profiling tools effectively
- ✅ Apply production-ready optimizations
Chapter 1: Performance Fundamentals
Understanding React Native Performance
React Native performance depends on three main threads:
- JavaScript Thread: Runs your app logic
- Main Thread: Handles UI rendering and user interactions
- Shadow Thread: Calculates layout
Common Performance Issues
1. JavaScript Thread Blocking: Heavy computations blocking the JS thread
2. Bridge Communication: Excessive data transfer between JS and native
3. Memory Leaks: Unreleased objects causing memory growth
4. Inefficient Rendering: Unnecessary re-renders and large component trees
Performance Metrics to Track
- Time to Interactive (TTI): How quickly users can interact
- Bundle Size: JavaScript bundle size affects startup time
- Memory Usage: RAM consumption over time
- Frame Rate: Smooth 60 FPS for optimal UX
Chapter 2: Bundle Size Optimization
Analyzing Bundle Size
Use Metro Bundle Analyzer to understand your bundle composition:
``bash
npx react-native-bundle-visualizer
`
Tree Shaking and Dead Code Elimination
Import Only What You Need
`javascript
// ❌ Bad: Imports entire library
import _ from 'lodash';
// ✅ Good: Import specific functions
import { debounce } from 'lodash';
`
Use Babel Plugins
`json
{
"plugins": [
["import", {
"libraryName": "lodash",
"libraryDirectory": "",
"camel2DashComponentName": false
}, "lodash"]
]
}
`
Code Splitting Strategies
Dynamic Imports
`javascript
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
}>
);
}
`
Route-Based Splitting
`javascript
const HomeScreen = React.lazy(() => import('./screens/HomeScreen'));
const ProfileScreen = React.lazy(() => import('./screens/ProfileScreen'));
`
Chapter 3: Memory Management
Identifying Memory Leaks
Common Causes
- Event listeners not removed
- Timers not cleared
- Circular references
- Large objects in closures
Memory Leak Prevention
`javascript
useEffect(() => {
const subscription = EventEmitter.addListener('event', handler);
const timer = setInterval(updateData, 1000);
return () => {
subscription.remove();
clearInterval(timer);
};
}, []);
`
Efficient Data Structures
Use Immutable Updates
`javascript
// ❌ Bad: Mutating state
state.items.push(newItem);
// ✅ Good: Immutable update
setState(prevState => ({
...prevState,
items: [...prevState.items, newItem]
}));
`
Optimize Large Lists
`javascript
import { FlatList } from 'react-native';
data={items}
renderItem={renderItem}
keyExtractor={item => item.id}
removeClippedSubviews={true}
maxToRenderPerBatch={10}
windowSize={10}
/>
`
Chapter 4: Rendering Optimization
React.memo and useMemo
Prevent Unnecessary Re-renders
`javascript
const ExpensiveComponent = React.memo(({ data }) => {
const processedData = useMemo(() => {
return data.map(item => expensiveOperation(item));
}, [data]);
return {/* Render processed data */} ;
});
`
useCallback for Event Handlers
`javascript
const ListItem = React.memo(({ item, onPress }) => {
const handlePress = useCallback(() => {
onPress(item.id);
}, [item.id, onPress]);
return (
{item.title}
);
});
`
Virtualization for Large Lists
`javascript
import { VirtualizedList } from 'react-native';
data={largeDataSet}
initialNumToRender={4}
renderItem={({ item }) => }
keyExtractor={item => item.id}
getItemCount={() => largeDataSet.length}
getItem={(data, index) => data[index]}
/>
`
Chapter 5: Navigation Performance
Optimize Screen Transitions
Lazy Loading Screens
`javascript
const LazyScreen = () => {
const Component = React.lazy(() => import('./HeavyScreen'));
return (
}>
);
};
`
Preload Critical Screens
`javascript
// Preload next screen during idle time
const preloadScreen = () => {
import('./NextScreen');
};
useEffect(() => {
const timer = setTimeout(preloadScreen, 2000);
return () => clearTimeout(timer);
}, []);
`
Stack Navigator Optimization
`javascript
screenOptions={{
headerShown: false,
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
}}
initialRouteName="Home"
>
name="Home"
component={HomeScreen}
options={{ lazy: false }} // Preload important screens
/>
`
Chapter 6: Image and Asset Optimization
Image Optimization Strategies
Use Appropriate Formats
- WebP: Best compression for photos
- PNG: For images with transparency
- SVG: For simple graphics and icons
Implement Progressive Loading
`javascript
const OptimizedImage = ({ source, placeholder }) => {
const [loaded, setLoaded] = useState(false);
return (
{!loaded && }
source={source}
onLoad={() => setLoaded(true)}
style={{ opacity: loaded ? 1 : 0 }}
/>
);
};
`
Asset Bundling Best Practices
Use require() for Static Assets
`javascript
// ❌ Bad: Dynamic require
const imageName = 'logo';
const image = require(
./images/${imageName}.png);
// ✅ Good: Static require
const image = require('./images/logo.png');
`
Chapter 7: Profiling and Debugging
React DevTools Profiler
1. Install React DevTools
2. Enable profiling in your app
3. Record performance sessions
4. Analyze component render times
Flipper Performance Tools
Memory Profiler
- Track memory usage over time
- Identify memory leaks
- Analyze heap snapshots
Network Inspector
- Monitor API calls
- Optimize request/response sizes
- Identify slow endpoints
Custom Performance Monitoring
`javascript
const performanceMonitor = {
startTimer: (name) => {
console.time(name);
},
endTimer: (name) => {
console.timeEnd(name);
},
measureRender: (componentName) => {
return (WrappedComponent) => {
return (props) => {
performanceMonitor.startTimer(
${componentName} render);
useEffect(() => {
performanceMonitor.endTimer(
${componentName} render);
});
return ;
};
};
}
};
`
Chapter 8: Production Optimization
Build Optimization
Enable Hermes Engine
`javascript
// android/app/build.gradle
project.ext.react = [
enableHermes: true
]
`
Optimize Metro Configuration
`javascript
// metro.config.js
module.exports = {
transformer: {
minifierConfig: {
keep_fnames: true,
mangle: {
keep_fnames: true,
},
},
},
};
`
Runtime Performance
Implement Error Boundaries
`javascript
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// Log error to monitoring service
console.error('Error caught by boundary:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return ;
}
return this.props.children;
}
}
`
Monitoring and Analytics
Performance Metrics Collection
`javascript
import { Performance } from 'react-native-performance';
// Track app startup time
Performance.mark('app-start');
Performance.mark('app-interactive');
Performance.measure('startup-time', 'app-start', 'app-interactive');
``
Best Practices Summary
1. Profile First: Always measure before optimizing
2. Optimize Gradually: Make incremental improvements
3. Test on Real Devices: Emulators don't reflect real performance
4. Monitor Production: Use crash reporting and performance monitoring
5. Keep Dependencies Updated: Newer versions often include performance improvements
Conclusion
Performance optimization is an ongoing process. Start with the biggest impact optimizations and gradually refine your app's performance. Remember to always measure the impact of your changes and test on real devices.
Ready to optimize your app's icons? Use our [Icon Generator](/) for perfectly optimized app icons!
- ✅ Identify and fix performance bottlenecks
- ✅ Optimize bundle size and startup time
- ✅ Implement efficient memory management
- ✅ Master rendering optimization techniques
- ✅ Use profiling tools effectively
- ✅ Apply production-ready optimizations
Chapter 1: Performance Fundamentals
Understanding React Native Performance
React Native performance depends on three main threads:
- JavaScript Thread: Runs your app logic
- Main Thread: Handles UI rendering and user interactions
- Shadow Thread: Calculates layout
Common Performance Issues
1. JavaScript Thread Blocking: Heavy computations blocking the JS thread
2. Bridge Communication: Excessive data transfer between JS and native
3. Memory Leaks: Unreleased objects causing memory growth
4. Inefficient Rendering: Unnecessary re-renders and large component trees
Performance Metrics to Track
- Time to Interactive (TTI): How quickly users can interact
- Bundle Size: JavaScript bundle size affects startup time
- Memory Usage: RAM consumption over time
- Frame Rate: Smooth 60 FPS for optimal UX
Chapter 2: Bundle Size Optimization
Analyzing Bundle Size
Use Metro Bundle Analyzer to understand your bundle composition:
``bash
npx react-native-bundle-visualizer
`
Tree Shaking and Dead Code Elimination
Import Only What You Need
`javascript
// ❌ Bad: Imports entire library
import _ from 'lodash';
// ✅ Good: Import specific functions
import { debounce } from 'lodash';
`
Use Babel Plugins
`json
{
"plugins": [
["import", {
"libraryName": "lodash",
"libraryDirectory": "",
"camel2DashComponentName": false
}, "lodash"]
]
}
`
Code Splitting Strategies
Dynamic Imports
`javascript
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
}>
);
}
`
Route-Based Splitting
`javascript
const HomeScreen = React.lazy(() => import('./screens/HomeScreen'));
const ProfileScreen = React.lazy(() => import('./screens/ProfileScreen'));
`
Chapter 3: Memory Management
Identifying Memory Leaks
Common Causes
- Event listeners not removed
- Timers not cleared
- Circular references
- Large objects in closures
Memory Leak Prevention
`javascript
useEffect(() => {
const subscription = EventEmitter.addListener('event', handler);
const timer = setInterval(updateData, 1000);
return () => {
subscription.remove();
clearInterval(timer);
};
}, []);
`
Efficient Data Structures
Use Immutable Updates
`javascript
// ❌ Bad: Mutating state
state.items.push(newItem);
// ✅ Good: Immutable update
setState(prevState => ({
...prevState,
items: [...prevState.items, newItem]
}));
`
Optimize Large Lists
`javascript
import { FlatList } from 'react-native';
data={items}
renderItem={renderItem}
keyExtractor={item => item.id}
removeClippedSubviews={true}
maxToRenderPerBatch={10}
windowSize={10}
/>
`
Chapter 4: Rendering Optimization
React.memo and useMemo
Prevent Unnecessary Re-renders
`javascript
const ExpensiveComponent = React.memo(({ data }) => {
const processedData = useMemo(() => {
return data.map(item => expensiveOperation(item));
}, [data]);
return {/* Render processed data */} ;
});
`
useCallback for Event Handlers
`javascript
const ListItem = React.memo(({ item, onPress }) => {
const handlePress = useCallback(() => {
onPress(item.id);
}, [item.id, onPress]);
return (
{item.title}
);
});
`
Virtualization for Large Lists
`javascript
import { VirtualizedList } from 'react-native';
data={largeDataSet}
initialNumToRender={4}
renderItem={({ item }) => }
keyExtractor={item => item.id}
getItemCount={() => largeDataSet.length}
getItem={(data, index) => data[index]}
/>
`
Chapter 5: Navigation Performance
Optimize Screen Transitions
Lazy Loading Screens
`javascript
const LazyScreen = () => {
const Component = React.lazy(() => import('./HeavyScreen'));
return (
}>
);
};
`
Preload Critical Screens
`javascript
// Preload next screen during idle time
const preloadScreen = () => {
import('./NextScreen');
};
useEffect(() => {
const timer = setTimeout(preloadScreen, 2000);
return () => clearTimeout(timer);
}, []);
`
Stack Navigator Optimization
`javascript
screenOptions={{
headerShown: false,
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
}}
initialRouteName="Home"
>
name="Home"
component={HomeScreen}
options={{ lazy: false }} // Preload important screens
/>
`
Chapter 6: Image and Asset Optimization
Image Optimization Strategies
Use Appropriate Formats
- WebP: Best compression for photos
- PNG: For images with transparency
- SVG: For simple graphics and icons
Implement Progressive Loading
`javascript
const OptimizedImage = ({ source, placeholder }) => {
const [loaded, setLoaded] = useState(false);
return (
{!loaded && }
source={source}
onLoad={() => setLoaded(true)}
style={{ opacity: loaded ? 1 : 0 }}
/>
);
};
`
Asset Bundling Best Practices
Use require() for Static Assets
`javascript
// ❌ Bad: Dynamic require
const imageName = 'logo';
const image = require(
./images/${imageName}.png);
// ✅ Good: Static require
const image = require('./images/logo.png');
`
Chapter 7: Profiling and Debugging
React DevTools Profiler
1. Install React DevTools
2. Enable profiling in your app
3. Record performance sessions
4. Analyze component render times
Flipper Performance Tools
Memory Profiler
- Track memory usage over time
- Identify memory leaks
- Analyze heap snapshots
Network Inspector
- Monitor API calls
- Optimize request/response sizes
- Identify slow endpoints
Custom Performance Monitoring
`javascript
const performanceMonitor = {
startTimer: (name) => {
console.time(name);
},
endTimer: (name) => {
console.timeEnd(name);
},
measureRender: (componentName) => {
return (WrappedComponent) => {
return (props) => {
performanceMonitor.startTimer(
${componentName} render);
useEffect(() => {
performanceMonitor.endTimer(
${componentName} render);
});
return ;
};
};
}
};
`
Chapter 8: Production Optimization
Build Optimization
Enable Hermes Engine
`javascript
// android/app/build.gradle
project.ext.react = [
enableHermes: true
]
`
Optimize Metro Configuration
`javascript
// metro.config.js
module.exports = {
transformer: {
minifierConfig: {
keep_fnames: true,
mangle: {
keep_fnames: true,
},
},
},
};
`
Runtime Performance
Implement Error Boundaries
`javascript
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// Log error to monitoring service
console.error('Error caught by boundary:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return ;
}
return this.props.children;
}
}
`
Monitoring and Analytics
Performance Metrics Collection
`javascript
import { Performance } from 'react-native-performance';
// Track app startup time
Performance.mark('app-start');
Performance.mark('app-interactive');
Performance.measure('startup-time', 'app-start', 'app-interactive');
``
Best Practices Summary
1. Profile First: Always measure before optimizing
2. Optimize Gradually: Make incremental improvements
3. Test on Real Devices: Emulators don't reflect real performance
4. Monitor Production: Use crash reporting and performance monitoring
5. Keep Dependencies Updated: Newer versions often include performance improvements
Conclusion
Performance optimization is an ongoing process. Start with the biggest impact optimizations and gradually refine your app's performance. Remember to always measure the impact of your changes and test on real devices.
Ready to optimize your app's icons? Use our [Icon Generator](/) for perfectly optimized app icons!
React Native performance depends on three main threads:
- JavaScript Thread: Runs your app logic
- Main Thread: Handles UI rendering and user interactions
- Shadow Thread: Calculates layout
Common Performance Issues
1. JavaScript Thread Blocking: Heavy computations blocking the JS thread
2. Bridge Communication: Excessive data transfer between JS and native
3. Memory Leaks: Unreleased objects causing memory growth
4. Inefficient Rendering: Unnecessary re-renders and large component trees
Performance Metrics to Track
- Time to Interactive (TTI): How quickly users can interact
- Bundle Size: JavaScript bundle size affects startup time
- Memory Usage: RAM consumption over time
- Frame Rate: Smooth 60 FPS for optimal UX
Chapter 2: Bundle Size Optimization
Analyzing Bundle Size
Use Metro Bundle Analyzer to understand your bundle composition:
``bash
npx react-native-bundle-visualizer
`
Tree Shaking and Dead Code Elimination
Import Only What You Need
`javascript
// ❌ Bad: Imports entire library
import _ from 'lodash';
// ✅ Good: Import specific functions
import { debounce } from 'lodash';
`
Use Babel Plugins
`json
{
"plugins": [
["import", {
"libraryName": "lodash",
"libraryDirectory": "",
"camel2DashComponentName": false
}, "lodash"]
]
}
`
Code Splitting Strategies
Dynamic Imports
`javascript
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
}>
);
}
`
Route-Based Splitting
`javascript
const HomeScreen = React.lazy(() => import('./screens/HomeScreen'));
const ProfileScreen = React.lazy(() => import('./screens/ProfileScreen'));
`
Chapter 3: Memory Management
Identifying Memory Leaks
Common Causes
- Event listeners not removed
- Timers not cleared
- Circular references
- Large objects in closures
Memory Leak Prevention
`javascript
useEffect(() => {
const subscription = EventEmitter.addListener('event', handler);
const timer = setInterval(updateData, 1000);
return () => {
subscription.remove();
clearInterval(timer);
};
}, []);
`
Efficient Data Structures
Use Immutable Updates
`javascript
// ❌ Bad: Mutating state
state.items.push(newItem);
// ✅ Good: Immutable update
setState(prevState => ({
...prevState,
items: [...prevState.items, newItem]
}));
`
Optimize Large Lists
`javascript
import { FlatList } from 'react-native';
data={items}
renderItem={renderItem}
keyExtractor={item => item.id}
removeClippedSubviews={true}
maxToRenderPerBatch={10}
windowSize={10}
/>
`
Chapter 4: Rendering Optimization
React.memo and useMemo
Prevent Unnecessary Re-renders
`javascript
const ExpensiveComponent = React.memo(({ data }) => {
const processedData = useMemo(() => {
return data.map(item => expensiveOperation(item));
}, [data]);
return {/* Render processed data */} ;
});
`
useCallback for Event Handlers
`javascript
const ListItem = React.memo(({ item, onPress }) => {
const handlePress = useCallback(() => {
onPress(item.id);
}, [item.id, onPress]);
return (
{item.title}
);
});
`
Virtualization for Large Lists
`javascript
import { VirtualizedList } from 'react-native';
data={largeDataSet}
initialNumToRender={4}
renderItem={({ item }) => }
keyExtractor={item => item.id}
getItemCount={() => largeDataSet.length}
getItem={(data, index) => data[index]}
/>
`
Chapter 5: Navigation Performance
Optimize Screen Transitions
Lazy Loading Screens
`javascript
const LazyScreen = () => {
const Component = React.lazy(() => import('./HeavyScreen'));
return (
}>
);
};
`
Preload Critical Screens
`javascript
// Preload next screen during idle time
const preloadScreen = () => {
import('./NextScreen');
};
useEffect(() => {
const timer = setTimeout(preloadScreen, 2000);
return () => clearTimeout(timer);
}, []);
`
Stack Navigator Optimization
`javascript
screenOptions={{
headerShown: false,
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
}}
initialRouteName="Home"
>
name="Home"
component={HomeScreen}
options={{ lazy: false }} // Preload important screens
/>
`
Chapter 6: Image and Asset Optimization
Image Optimization Strategies
Use Appropriate Formats
- WebP: Best compression for photos
- PNG: For images with transparency
- SVG: For simple graphics and icons
Implement Progressive Loading
`javascript
const OptimizedImage = ({ source, placeholder }) => {
const [loaded, setLoaded] = useState(false);
return (
{!loaded && }
source={source}
onLoad={() => setLoaded(true)}
style={{ opacity: loaded ? 1 : 0 }}
/>
);
};
`
Asset Bundling Best Practices
Use require() for Static Assets
`javascript
// ❌ Bad: Dynamic require
const imageName = 'logo';
const image = require(
./images/${imageName}.png);
// ✅ Good: Static require
const image = require('./images/logo.png');
`
Chapter 7: Profiling and Debugging
React DevTools Profiler
1. Install React DevTools
2. Enable profiling in your app
3. Record performance sessions
4. Analyze component render times
Flipper Performance Tools
Memory Profiler
- Track memory usage over time
- Identify memory leaks
- Analyze heap snapshots
Network Inspector
- Monitor API calls
- Optimize request/response sizes
- Identify slow endpoints
Custom Performance Monitoring
`javascript
const performanceMonitor = {
startTimer: (name) => {
console.time(name);
},
endTimer: (name) => {
console.timeEnd(name);
},
measureRender: (componentName) => {
return (WrappedComponent) => {
return (props) => {
performanceMonitor.startTimer(
${componentName} render);
useEffect(() => {
performanceMonitor.endTimer(
${componentName} render);
});
return ;
};
};
}
};
`
Chapter 8: Production Optimization
Build Optimization
Enable Hermes Engine
`javascript
// android/app/build.gradle
project.ext.react = [
enableHermes: true
]
`
Optimize Metro Configuration
`javascript
// metro.config.js
module.exports = {
transformer: {
minifierConfig: {
keep_fnames: true,
mangle: {
keep_fnames: true,
},
},
},
};
`
Runtime Performance
Implement Error Boundaries
`javascript
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// Log error to monitoring service
console.error('Error caught by boundary:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return ;
}
return this.props.children;
}
}
`
Monitoring and Analytics
Performance Metrics Collection
`javascript
import { Performance } from 'react-native-performance';
// Track app startup time
Performance.mark('app-start');
Performance.mark('app-interactive');
Performance.measure('startup-time', 'app-start', 'app-interactive');
``
Best Practices Summary
1. Profile First: Always measure before optimizing
2. Optimize Gradually: Make incremental improvements
3. Test on Real Devices: Emulators don't reflect real performance
4. Monitor Production: Use crash reporting and performance monitoring
5. Keep Dependencies Updated: Newer versions often include performance improvements
Conclusion
Performance optimization is an ongoing process. Start with the biggest impact optimizations and gradually refine your app's performance. Remember to always measure the impact of your changes and test on real devices.
Ready to optimize your app's icons? Use our [Icon Generator](/) for perfectly optimized app icons!
- Time to Interactive (TTI): How quickly users can interact
- Bundle Size: JavaScript bundle size affects startup time
- Memory Usage: RAM consumption over time
- Frame Rate: Smooth 60 FPS for optimal UX
Chapter 2: Bundle Size Optimization
Analyzing Bundle Size
Use Metro Bundle Analyzer to understand your bundle composition:
``bash
npx react-native-bundle-visualizer
`
Tree Shaking and Dead Code Elimination
Import Only What You Need
`javascript
// ❌ Bad: Imports entire library
import _ from 'lodash';
// ✅ Good: Import specific functions
import { debounce } from 'lodash';
`
Use Babel Plugins
`json
{
"plugins": [
["import", {
"libraryName": "lodash",
"libraryDirectory": "",
"camel2DashComponentName": false
}, "lodash"]
]
}
`
Code Splitting Strategies
Dynamic Imports
`javascript
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
}>
);
}
`
Route-Based Splitting
`javascript
const HomeScreen = React.lazy(() => import('./screens/HomeScreen'));
const ProfileScreen = React.lazy(() => import('./screens/ProfileScreen'));
`
Chapter 3: Memory Management
Identifying Memory Leaks
Common Causes
- Event listeners not removed
- Timers not cleared
- Circular references
- Large objects in closures
Memory Leak Prevention
`javascript
useEffect(() => {
const subscription = EventEmitter.addListener('event', handler);
const timer = setInterval(updateData, 1000);
return () => {
subscription.remove();
clearInterval(timer);
};
}, []);
`
Efficient Data Structures
Use Immutable Updates
`javascript
// ❌ Bad: Mutating state
state.items.push(newItem);
// ✅ Good: Immutable update
setState(prevState => ({
...prevState,
items: [...prevState.items, newItem]
}));
`
Optimize Large Lists
`javascript
import { FlatList } from 'react-native';
data={items}
renderItem={renderItem}
keyExtractor={item => item.id}
removeClippedSubviews={true}
maxToRenderPerBatch={10}
windowSize={10}
/>
`
Chapter 4: Rendering Optimization
React.memo and useMemo
Prevent Unnecessary Re-renders
`javascript
const ExpensiveComponent = React.memo(({ data }) => {
const processedData = useMemo(() => {
return data.map(item => expensiveOperation(item));
}, [data]);
return {/* Render processed data */} ;
});
`
useCallback for Event Handlers
`javascript
const ListItem = React.memo(({ item, onPress }) => {
const handlePress = useCallback(() => {
onPress(item.id);
}, [item.id, onPress]);
return (
{item.title}
);
});
`
Virtualization for Large Lists
`javascript
import { VirtualizedList } from 'react-native';
data={largeDataSet}
initialNumToRender={4}
renderItem={({ item }) => }
keyExtractor={item => item.id}
getItemCount={() => largeDataSet.length}
getItem={(data, index) => data[index]}
/>
`
Chapter 5: Navigation Performance
Optimize Screen Transitions
Lazy Loading Screens
`javascript
const LazyScreen = () => {
const Component = React.lazy(() => import('./HeavyScreen'));
return (
}>
);
};
`
Preload Critical Screens
`javascript
// Preload next screen during idle time
const preloadScreen = () => {
import('./NextScreen');
};
useEffect(() => {
const timer = setTimeout(preloadScreen, 2000);
return () => clearTimeout(timer);
}, []);
`
Stack Navigator Optimization
`javascript
screenOptions={{
headerShown: false,
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
}}
initialRouteName="Home"
>
name="Home"
component={HomeScreen}
options={{ lazy: false }} // Preload important screens
/>
`
Chapter 6: Image and Asset Optimization
Image Optimization Strategies
Use Appropriate Formats
- WebP: Best compression for photos
- PNG: For images with transparency
- SVG: For simple graphics and icons
Implement Progressive Loading
`javascript
const OptimizedImage = ({ source, placeholder }) => {
const [loaded, setLoaded] = useState(false);
return (
{!loaded && }
source={source}
onLoad={() => setLoaded(true)}
style={{ opacity: loaded ? 1 : 0 }}
/>
);
};
`
Asset Bundling Best Practices
Use require() for Static Assets
`javascript
// ❌ Bad: Dynamic require
const imageName = 'logo';
const image = require(
./images/${imageName}.png);
// ✅ Good: Static require
const image = require('./images/logo.png');
`
Chapter 7: Profiling and Debugging
React DevTools Profiler
1. Install React DevTools
2. Enable profiling in your app
3. Record performance sessions
4. Analyze component render times
Flipper Performance Tools
Memory Profiler
- Track memory usage over time
- Identify memory leaks
- Analyze heap snapshots
Network Inspector
- Monitor API calls
- Optimize request/response sizes
- Identify slow endpoints
Custom Performance Monitoring
`javascript
const performanceMonitor = {
startTimer: (name) => {
console.time(name);
},
endTimer: (name) => {
console.timeEnd(name);
},
measureRender: (componentName) => {
return (WrappedComponent) => {
return (props) => {
performanceMonitor.startTimer(
${componentName} render);
useEffect(() => {
performanceMonitor.endTimer(
${componentName} render);
});
return ;
};
};
}
};
`
Chapter 8: Production Optimization
Build Optimization
Enable Hermes Engine
`javascript
// android/app/build.gradle
project.ext.react = [
enableHermes: true
]
`
Optimize Metro Configuration
`javascript
// metro.config.js
module.exports = {
transformer: {
minifierConfig: {
keep_fnames: true,
mangle: {
keep_fnames: true,
},
},
},
};
`
Runtime Performance
Implement Error Boundaries
`javascript
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// Log error to monitoring service
console.error('Error caught by boundary:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return ;
}
return this.props.children;
}
}
`
Monitoring and Analytics
Performance Metrics Collection
`javascript
import { Performance } from 'react-native-performance';
// Track app startup time
Performance.mark('app-start');
Performance.mark('app-interactive');
Performance.measure('startup-time', 'app-start', 'app-interactive');
``
Best Practices Summary
1. Profile First: Always measure before optimizing
2. Optimize Gradually: Make incremental improvements
3. Test on Real Devices: Emulators don't reflect real performance
4. Monitor Production: Use crash reporting and performance monitoring
5. Keep Dependencies Updated: Newer versions often include performance improvements
Conclusion
Performance optimization is an ongoing process. Start with the biggest impact optimizations and gradually refine your app's performance. Remember to always measure the impact of your changes and test on real devices.
Ready to optimize your app's icons? Use our [Icon Generator](/) for perfectly optimized app icons!
Use Metro Bundle Analyzer to understand your bundle composition:
``
bash
npx react-native-bundle-visualizer
`
Tree Shaking and Dead Code Elimination
Import Only What You Need
`javascript
// ❌ Bad: Imports entire library
import _ from 'lodash';
// ✅ Good: Import specific functions
import { debounce } from 'lodash';
`
Use Babel Plugins
`json
{
"plugins": [
["import", {
"libraryName": "lodash",
"libraryDirectory": "",
"camel2DashComponentName": false
}, "lodash"]
]
}
`
Code Splitting Strategies
Dynamic Imports
`javascript
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
}>
);
}
`
Route-Based Splitting
`javascript
const HomeScreen = React.lazy(() => import('./screens/HomeScreen'));
const ProfileScreen = React.lazy(() => import('./screens/ProfileScreen'));
`
Chapter 3: Memory Management
Identifying Memory Leaks
Common Causes
- Event listeners not removed
- Timers not cleared
- Circular references
- Large objects in closures
Memory Leak Prevention
`javascript
useEffect(() => {
const subscription = EventEmitter.addListener('event', handler);
const timer = setInterval(updateData, 1000);
return () => {
subscription.remove();
clearInterval(timer);
};
}, []);
`
Efficient Data Structures
Use Immutable Updates
`javascript
// ❌ Bad: Mutating state
state.items.push(newItem);
// ✅ Good: Immutable update
setState(prevState => ({
...prevState,
items: [...prevState.items, newItem]
}));
`
Optimize Large Lists
`javascript
import { FlatList } from 'react-native';
data={items}
renderItem={renderItem}
keyExtractor={item => item.id}
removeClippedSubviews={true}
maxToRenderPerBatch={10}
windowSize={10}
/>
`
Chapter 4: Rendering Optimization
React.memo and useMemo
Prevent Unnecessary Re-renders
`javascript
const ExpensiveComponent = React.memo(({ data }) => {
const processedData = useMemo(() => {
return data.map(item => expensiveOperation(item));
}, [data]);
return {/* Render processed data */} ;
});
`
useCallback for Event Handlers
`javascript
const ListItem = React.memo(({ item, onPress }) => {
const handlePress = useCallback(() => {
onPress(item.id);
}, [item.id, onPress]);
return (
{item.title}
);
});
`
Virtualization for Large Lists
`javascript
import { VirtualizedList } from 'react-native';
data={largeDataSet}
initialNumToRender={4}
renderItem={({ item }) => }
keyExtractor={item => item.id}
getItemCount={() => largeDataSet.length}
getItem={(data, index) => data[index]}
/>
`
Chapter 5: Navigation Performance
Optimize Screen Transitions
Lazy Loading Screens
`javascript
const LazyScreen = () => {
const Component = React.lazy(() => import('./HeavyScreen'));
return (
}>
);
};
`
Preload Critical Screens
`javascript
// Preload next screen during idle time
const preloadScreen = () => {
import('./NextScreen');
};
useEffect(() => {
const timer = setTimeout(preloadScreen, 2000);
return () => clearTimeout(timer);
}, []);
`
Stack Navigator Optimization
`javascript
screenOptions={{
headerShown: false,
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
}}
initialRouteName="Home"
>
name="Home"
component={HomeScreen}
options={{ lazy: false }} // Preload important screens
/>
`
Chapter 6: Image and Asset Optimization
Image Optimization Strategies
Use Appropriate Formats
- WebP: Best compression for photos
- PNG: For images with transparency
- SVG: For simple graphics and icons
Implement Progressive Loading
`javascript
const OptimizedImage = ({ source, placeholder }) => {
const [loaded, setLoaded] = useState(false);
return (
{!loaded && }
source={source}
onLoad={() => setLoaded(true)}
style={{ opacity: loaded ? 1 : 0 }}
/>
);
};
`
Asset Bundling Best Practices
Use require() for Static Assets
`javascript
// ❌ Bad: Dynamic require
const imageName = 'logo';
const image = require(
./images/${imageName}.png);
// ✅ Good: Static require
const image = require('./images/logo.png');
`
Chapter 7: Profiling and Debugging
React DevTools Profiler
1. Install React DevTools
2. Enable profiling in your app
3. Record performance sessions
4. Analyze component render times
Flipper Performance Tools
Memory Profiler
- Track memory usage over time
- Identify memory leaks
- Analyze heap snapshots
Network Inspector
- Monitor API calls
- Optimize request/response sizes
- Identify slow endpoints
Custom Performance Monitoring
`javascript
const performanceMonitor = {
startTimer: (name) => {
console.time(name);
},
endTimer: (name) => {
console.timeEnd(name);
},
measureRender: (componentName) => {
return (WrappedComponent) => {
return (props) => {
performanceMonitor.startTimer(
${componentName} render);
useEffect(() => {
performanceMonitor.endTimer(
${componentName} render);
});
return ;
};
};
}
};
`
Chapter 8: Production Optimization
Build Optimization
Enable Hermes Engine
`javascript
// android/app/build.gradle
project.ext.react = [
enableHermes: true
]
`
Optimize Metro Configuration
`javascript
// metro.config.js
module.exports = {
transformer: {
minifierConfig: {
keep_fnames: true,
mangle: {
keep_fnames: true,
},
},
},
};
`
Runtime Performance
Implement Error Boundaries
`javascript
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// Log error to monitoring service
console.error('Error caught by boundary:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return ;
}
return this.props.children;
}
}
`
Monitoring and Analytics
Performance Metrics Collection
`javascript
import { Performance } from 'react-native-performance';
// Track app startup time
Performance.mark('app-start');
Performance.mark('app-interactive');
Performance.measure('startup-time', 'app-start', 'app-interactive');
``Best Practices Summary
1. Profile First: Always measure before optimizing
2. Optimize Gradually: Make incremental improvements
3. Test on Real Devices: Emulators don't reflect real performance
4. Monitor Production: Use crash reporting and performance monitoring
5. Keep Dependencies Updated: Newer versions often include performance improvements
Conclusion
Performance optimization is an ongoing process. Start with the biggest impact optimizations and gradually refine your app's performance. Remember to always measure the impact of your changes and test on real devices.
Ready to optimize your app's icons? Use our [Icon Generator](/) for perfectly optimized app icons!
Performance optimization is an ongoing process. Start with the biggest impact optimizations and gradually refine your app's performance. Remember to always measure the impact of your changes and test on real devices.
Ready to optimize your app's icons? Use our [Icon Generator](/) for perfectly optimized app icons!