Most React apps start fast and slow down over time. Extra re-renders pile up, bundles grow, and large lists block the main thread. Here are the techniques that actually move the needle — from render control and virtualization to code splitting and SSR.
1. React Rendering Mechanism Optimization
React uses a virtual DOM to efficiently update the user interface. However, unnecessary re-renders can impact performance. Here’s how to optimize rendering:
1.1 Using React.memo and PureComponent
-
React.memo: Prevents re-renders for function components when props remain unchanged. -
PureComponent: Optimizes class components by shallowly comparing props and state.
Example: React.memo
const ChildComponent = React.memo(({ value }) => {
console.log('ChildComponent rendered');
return <div>{value}</div>;
});
const ParentComponent = () => {
const [count, setCount] = React.useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increase Count</button>
<ChildComponent value={count} />
</div>
);
};In this example, ChildComponent only re-renders when its value prop changes.
1.2 Using useMemo and useCallback
-
useMemo: Caches expensive computations. -
useCallback: Memoizes function references to avoid unnecessary re-creation.
Example: useMemo
const ExpensiveCalculation = ({ items }) => {
const total = React.useMemo(() => {
return items.reduce((sum, item) => sum + item.value, 0);
}, [items]);
return <div>Total: {total}</div>;
};Example: useCallback
const IncrementButton = () => {
const [count, setCount] = React.useState(0);
const increment = React.useCallback(() => {
setCount(prev => prev + 1);
}, []);
return <button onClick={increment}>Increment</button>;
};2. Virtualization for Large Data Sets
Rendering large lists or tables can degrade performance. Virtualization ensures only visible elements are rendered.
2.1 Using react-window
Install the library:
Example: Virtualized List
import { FixedSizeList as List } from 'react-window';
const Row = ({ index, style }) => <div style={style}>Item {index}</div>;
const VirtualizedList = () => (
<List height={400} itemCount={1000} itemSize={35} width={300}>
{Row}
</List>
);This renders only items visible within the viewport, reducing DOM nodes.
3. Lazy Loading and On-Demand Loading
3.1 Lazy Loading with React.lazy and Suspense
Lazy loading improves load times by deferring component loading until needed.
Example: Component Lazy Loading
const LazyComponent = React.lazy(() => import('./LazyComponent'));
const App = () => (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);3.2 Route-Based Lazy Loading with React Router
import React, { Suspense } from 'react';
import { Route, BrowserRouter as Router, Switch } from 'react-router-dom';
const HomePage = React.lazy(() => import('./HomePage'));
const AboutPage = React.lazy(() => import('./AboutPage'));
const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route path='/' exact component={HomePage} />
<Route path='/about' component={AboutPage} />
</Switch>
</Suspense>
</Router>
);4. Build Optimization Techniques
4.1 Enable React Production Mode
Ensure production builds by running:
4.2 Code Splitting with Webpack
Split bundles to load only necessary code:
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
},
},
};4.3 Tree Shaking
Remove unused code:
module.exports = {
mode: 'production',
};4.4 Analyze Bundle Size
Install webpack-bundle-analyzer:
Add to Webpack config:
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
plugins: [new BundleAnalyzerPlugin()],
};5. Server-Side Rendering (SSR) and Static Site Generation (SSG)
5.1 Server-Side Rendering with Next.js
Example: SSR with getServerSideProps
export async function getServerSideProps() {
const data = await fetchData();
return { props: { data } };
}
const Page = ({ data }) => <div>{data}</div>;
export default Page;5.2 Static Site Generation with Next.js
Example: SSG with getStaticProps
export async function getStaticProps() {
const data = await fetchData();
return { props: { data } };
}
const Page = ({ data }) => <div>{data}</div>;
export default Page;6. Image Optimization
6.1 Using next/image
import Image from 'next/image';
import Image from 'next/image';
const OptimizedImage = () => (
<Image
src='/path/to/image.jpg'
alt='Description'
width={500}
height={300}
priority
/>
);6.2 Lazy Loading with Placeholder Images
Install react-lazy-load-image-component:
Example:
import { LazyLoadImage } from 'react-lazy-load-image-component';
const LazyImage = () => (
<LazyLoadImage
alt='Image'
src='/path/to/image.jpg'
height='auto'
width='100%'
/>
);7. Conclusion
Start with the React DevTools profiler — find the components that re-render most, then apply React.memo, useMemo, or virtualization where the profiler shows the biggest wins. Code splitting and SSR are next once the render path is clean.