React Performance Optimization - Complete Guide
Published: September 25, 2024 | Reading time: 24 minutes
React Performance Overview
Optimizing React performance is crucial for delivering fast, responsive user experiences:
Performance Benefits
# React Performance Benefits
- Faster rendering
- Reduced bundle size
- Better user experience
- Lower memory usage
- Improved SEO
- Mobile optimization
- Cost efficiency
Component Optimization Techniques
React.memo and Pure Components
Component Optimization
# Component Optimization Techniques
# 1. React.memo for Functional Components
import React, { memo } from 'react';
const ExpensiveComponent = memo(({ data, onUpdate }) => {
console.log('ExpensiveComponent rendered');
return (
{data.title}
{data.description}
);
});
// Custom comparison function
const OptimizedComponent = memo(({ user, settings }) => {
return (
{user.name}
Theme: {settings.theme}
);
}, (prevProps, nextProps) => {
return (
prevProps.user.id === nextProps.user.id &&
prevProps.settings.theme === nextProps.settings.theme
);
});
# 2. PureComponent for Class Components
import React, { PureComponent } from 'react';
class OptimizedClassComponent extends PureComponent {
render() {
const { data, onUpdate } = this.props;
return (
{data.title}
{data.description}
);
}
}
# 3. useMemo Hook
import React, { useMemo, useState } from 'react';
const DataProcessor = ({ items, filter }) => {
const [count, setCount] = useState(0);
// Expensive calculation memoized
const filteredItems = useMemo(() => {
console.log('Filtering items...');
return items.filter(item =>
item.name.toLowerCase().includes(filter.toLowerCase())
);
}, [items, filter]);
// Expensive computation memoized
const expensiveValue = useMemo(() => {
console.log('Computing expensive value...');
return filteredItems.reduce((sum, item) => sum + item.value, 0);
}, [filteredItems]);
return (
Processed Data
Count: {count}
Total Value: {expensiveValue}
Items: {filteredItems.length}
);
};
# 4. useCallback Hook
import React, { useCallback, useState } from 'react';
const ParentComponent = () => {
const [count, setCount] = useState(0);
const [items, setItems] = useState([]);
// Memoized callback to prevent child re-renders
const handleAddItem = useCallback((newItem) => {
setItems(prev => [...prev, newItem]);
}, []);
// Memoized callback with dependencies
const handleUpdateItem = useCallback((id, updates) => {
setItems(prev => prev.map(item =>
item.id === id ? { ...item, ...updates } : item
));
}, []);
return (
Parent Component
Count: {count}
);
};
const ItemList = React.memo(({ items, onAddItem, onUpdateItem }) => {
return (
{items.map(item => (
))}
);
});
# 5. Lazy Loading Components
import React, { lazy, Suspense } from 'react';
// Lazy load heavy components
const HeavyComponent = lazy(() => import('./HeavyComponent'));
const ChartComponent = lazy(() => import('./ChartComponent'));
const DataTable = lazy(() => import('./DataTable'));
const App = () => {
const [showHeavy, setShowHeavy] = useState(false);
const [showChart, setShowChart] = useState(false);
return (
My App
{showHeavy && (
Loading heavy component... }>
)}
{showChart && (
Loading chart...
{visibleItems.map(item => (
{item.content}
))}
{item.title}
{item.description}
{memoizedItems.map(item => (
))}
);
};
# 10. Performance Monitoring Component
import React, { useEffect, useRef } from 'react';
const PerformanceMonitor = ({ componentName }) => {
const renderCount = useRef(0);
const startTime = useRef(performance.now());
useEffect(() => {
renderCount.current += 1;
const endTime = performance.now();
const renderTime = endTime - startTime.current;
console.log(`${componentName} render #${renderCount.current}: ${renderTime.toFixed(2)}ms`);
startTime.current = performance.now();
});
return null; // This component doesn't render anything
};
// Usage in components
const MyComponent = () => {
return (
My Component
Bundle Optimization
Webpack and Build Optimization
Bundle Optimization
# Bundle Optimization Techniques
# 1. Webpack Configuration
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].chunk.js',
clean: true
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
},
common: {
name: 'common',
minChunks: 2,
chunks: 'all',
enforce: true
}
}
},
usedExports: true,
sideEffects: false
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-react'],
plugins: [
'@babel/plugin-transform-runtime',
'@babel/plugin-syntax-dynamic-import'
]
}
}
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
]
};
# 2. Tree Shaking Configuration
// package.json
{
"sideEffects": false,
"dependencies": {
"lodash": "^4.17.21"
}
}
// Import only what you need
import { debounce, throttle } from 'lodash';
// Instead of
import _ from 'lodash';
# 3. Dynamic Imports
// Route-based code splitting
const HomePage = lazy(() => import('./pages/HomePage'));
const AboutPage = lazy(() => import('./pages/AboutPage'));
// Component-based code splitting
const HeavyComponent = lazy(() =>
import('./components/HeavyComponent').then(module => ({
default: module.HeavyComponent
}))
);
# 4. Bundle Analysis
// webpack-bundle-analyzer
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false,
reportFilename: 'bundle-report.html'
})
]
};
# 5. Compression Configuration
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
plugins: [
new CompressionPlugin({
algorithm: 'gzip',
test: /\.(js|css|html|svg)$/,
threshold: 8192,
minRatio: 0.8
})
]
};
# 6. Image Optimization
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.(jpe?g|png|gif|svg)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[name].[hash][ext]'
}
}
]
},
plugins: [
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminMinify,
options: {
plugins: [
['gifsicle', { interlaced: true }],
['jpegtran', { progressive: true }],
['optipng', { optimizationLevel: 5 }],
['svgo', { name: 'preset-default' }]
]
}
}
})
]
};
# 7. CSS Optimization
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css'
})
],
optimization: {
minimizer: [
new CssMinimizerPlugin()
]
}
};
# 8. Service Worker for Caching
// sw.js
const CACHE_NAME = 'my-app-cache-v1';
const urlsToCache = [
'/',
'/static/js/bundle.js',
'/static/css/main.css'
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => cache.addAll(urlsToCache))
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((response) => {
return response || fetch(event.request);
})
);
});
# 9. Preloading Critical Resources
// index.html
// React component
const PreloadComponent = () => {
useEffect(() => {
const link = document.createElement('link');
link.rel = 'preload';
link.href = '/api/critical-data';
link.as = 'fetch';
link.crossOrigin = 'anonymous';
document.head.appendChild(link);
}, []);
return null;
};
# 10. Bundle Size Monitoring
// webpack.config.js
const BundleSizePlugin = require('webpack-bundle-size-analyzer').WebpackBundleSizeAnalyzerPlugin;
module.exports = {
plugins: [
new BundleSizePlugin('./bundle-size-report.txt')
]
};
// package.json scripts
{
"scripts": {
"analyze": "webpack-bundle-analyzer build/static/js/*.js",
"build:analyze": "npm run build && npm run analyze"
}
}
Performance Monitoring
React Performance Tools
Performance Tools
- React DevTools Profiler
- Chrome DevTools
- Lighthouse
- Web Vitals
- Bundle Analyzer
- Performance API
- React.memo
Optimization Strategies
- Component memoization
- Code splitting
- Lazy loading
- Virtual scrolling
- Bundle optimization
- Image optimization
- Caching strategies
Summary
React performance optimization involves several key areas:
- Component Optimization: React.memo, useMemo, useCallback, and PureComponent
- Bundle Optimization: Code splitting, tree shaking, and compression
- Performance Monitoring: DevTools, Lighthouse, and Web Vitals
- Best Practices: Lazy loading, virtual scrolling, and caching
Need More Help?
Struggling with React performance optimization or need help implementing advanced optimization techniques? Our React experts can help you build faster, more efficient applications.
Get React Help