From 3 Seconds to 1.1 Seconds: How I Improved React App Performance by 65%
by Hamzah Ejaz, Software Engineer
At Centrox AI, I inherited a React application with 3.2-second load times. After systematic optimization, we achieved 1.1 seconds - a 65% improvement. Here's the playbook.
Initial Diagnosis
Before: 3.2s load time
- 850KB JavaScript bundle
- No code splitting
- Unnecessary re-renders
- Unoptimized images
- No lazy loading
Optimization Strategy
1. Code Splitting & Lazy Loading
// Before
import Dashboard from './components/Dashboard'
import Analytics from './components/Analytics'
// After - Route-based splitting
const Dashboard = lazy(() => import('./components/Dashboard'))
const Analytics = lazy(() => import('./components/Analytics'))
function App() {
return (
<Suspense fallback={<Loading />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/analytics" element={<Analytics />} />
</Routes>
</Suspense>
)
}
Result: Bundle reduced from 850KB → 320KB (initial load)
2. Memoization & React.memo
// Prevent unnecessary re-renders
const UserCard = React.memo(({ user }: { user: User }) => {
return <div>{user.name}</div>
}, (prevProps, nextProps) => {
return prevProps.user.id === nextProps.user.id
})
// useMemo for expensive calculations
const ExpensiveComponent = ({ data }) => {
const processedData = useMemo(() => {
return complexCalculation(data)
}, [data])
return <Chart data={processedData} />
}
3. Image Optimization
// Next.js Image component
import Image from 'next/image'
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority // Above fold
quality={85}
/>
// Lazy load images below fold
<Image
src="/product.jpg"
alt="Product"
width={400}
height={300}
loading="lazy"
/>
4. Virtual Scrolling for Large Lists
import { FixedSizeList } from 'react-window'
function LargeList({ items }) {
const Row = ({ index, style }) => (
<div style={style}>
{items[index].name}
</div>
)
return (
<FixedSizeList
height={600}
itemCount={items.length}
itemSize={50}
width="100%"
>
{Row}
</FixedSizeList>
)
}
5. Bundle Analysis
# Analyze bundle composition
npm run build -- --analyze
# Identify heavy dependencies
npx webpack-bundle-analyzer dist/stats.json
Findings:
- moment.js (288KB) → replaced with date-fns (13KB)
- lodash (70KB) → tree-shakable imports
- Removed unused dependencies
Results
After: 1.1s load time (65% improvement)
- Initial bundle: 320KB
- Lighthouse score: 92 → 98
- Time to Interactive: 1.8s → 0.9s
- First Contentful Paint: 2.1s → 0.7s
Key Takeaways
- Measure first: Use Lighthouse, Bundle Analyzer
- Code split aggressively: Per route, per feature
- Optimize images: Use Next.js Image, WebP format
- Memoize wisely: Profile before optimizing
- Lazy load everything: Below fold, modals, heavy components
Performance optimization isn't premature - it's essential for user experience.