React Performance Optimization: From 8s to 3.1s Load Time
Practical techniques for optimizing React applications, including code splitting, memoization, and reducing render counts
React Performance Optimization: From 8s to 3.1s Load Time
Performance optimization is crucial for user experience. In this post, I'll share how we reduced our app's load time from 8 seconds to 3.1 seconds at Flipkart.
The Problem
Our warehouse management application was suffering from:
- Long initial load times (8+ seconds)
- Excessive re-renders
- Large bundle sizes
- Poor Core Web Vitals scores
Optimization Strategies
1. Code Splitting
We implemented route-based code splitting using React.lazy:
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Reports = lazy(() => import('./pages/Reports'));
function App() {
return (
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/reports" element={<Reports />} />
</Routes>
</Suspense>
);
}Result: Reduced initial bundle from 2.5MB to 800KB
2. Reducing Re-renders
We used React.memo and useMemo strategically:
// Before: Re-rendered on every parent update
function ExpensiveComponent({ data }) {
return <div>{/* Complex rendering */}</div>;
}
// After: Only re-renders when data changes
const ExpensiveComponent = React.memo(({ data }) => {
const processedData = useMemo(() => {
return expensiveCalculation(data);
}, [data]);
return <div>{/* Complex rendering */}</div>;
});Result: Reduced render count by 50%, improved render duration by 50%
3. Debouncing API Calls
We implemented debouncing for search inputs:
import { useMemo } from 'react';
import debounce from 'lodash/debounce';
function SearchComponent() {
const debouncedSearch = useMemo(
() => debounce((query) => {
fetchResults(query);
}, 300),
[]
);
return (
<input
onChange={(e) => debouncedSearch(e.target.value)}
placeholder="Search..."
/>
);
}Result: Reduced API calls by 40%
4. Virtual Scrolling
For long lists, we implemented virtual scrolling:
import { FixedSizeList } from 'react-window';
function VirtualList({ items }) {
return (
<FixedSizeList
height={600}
itemCount={items.length}
itemSize={50}
width="100%"
>
{({ index, style }) => (
<div style={style}>
{items[index].name}
</div>
)}
</FixedSizeList>
);
}Result: Improved rendering performance for 1000+ item lists
5. Image Optimization
We used Next.js Image component with proper sizing:
import Image from 'next/image';
function ProductCard({ product }) {
return (
<Image
src={product.image}
alt={product.name}
width={300}
height={300}
loading="lazy"
placeholder="blur"
/>
);
}Key Takeaways
- Measure First: Use React DevTools Profiler to identify bottlenecks
- Code Split: Don't load everything upfront
- Memoize Wisely: Not everything needs memoization
- Debounce User Input: Reduce unnecessary API calls
- Optimize Images: Use modern formats and lazy loading
Performance optimization is an ongoing process. Regular monitoring and incremental improvements lead to the best results.