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

  1. Measure first: Use Lighthouse, Bundle Analyzer
  2. Code split aggressively: Per route, per feature
  3. Optimize images: Use Next.js Image, WebP format
  4. Memoize wisely: Profile before optimizing
  5. Lazy load everything: Below fold, modals, heavy components

Performance optimization isn't premature - it's essential for user experience.

More articles

Building AI-Powered Meeting Intelligence: Lessons from EVA Meet

A deep dive into architecting an enterprise AI platform that combines GPT-4, Perplexity AI, and Deepgram for real-time meeting intelligence.

Read more

Full Stack MERN to AI Engineer: My Journey

How I transitioned from traditional full-stack development to AI engineering, the skills I acquired, and lessons for developers making the same journey.

Read more

Ready to Transform Your Business?

Get in touch today to learn how technology can revolutionize your operations!