Optimizing React Applications

Katlego Morwamohube
Software Developer & Security Specialist

React's virtual DOM is fast, but that doesn't mean React applications are fast by default. As your application grows, performance bottlenecks emerge. The good news? Most can be eliminated with strategic optimization.

60fps
Target Frame Rate
<100ms
Input Response Time
<1.8s
Largest Contentful Paint
<300ms
First Input Delay

Understanding React's Render Cycle

Before optimizing, understand when React re-renders:

Problem: Unnecessary Re-renders
// Bad: New object reference every render
function Parent() {
    const [count, setCount] = useState(0);
    
    const config = { threshold: 10 }; // New object every render!
    
    return <Child config={config} />; // Child re-renders unnecessarily
}
Solution: useMemo
// Good: Stable reference
function Parent() {
    const [count, setCount] = useState(0);
    
    const config = useMemo(() => ({ 
        threshold: 10 
    }), []); // Only created once
    
    return <Child config={config} />;
}

Code Splitting & Lazy Loading

Don't ship code the user doesn't immediately need. React.lazy and Suspense make this trivial:

Route-Based Splitting
import { lazy, Suspense } from 'react';
import { Routes, Route } from 'react-router-dom';

const Dashboard = lazy(() => import('./Dashboard'));
const Analytics = lazy(() => import('./Analytics'));
const Settings = lazy(() => import('./Settings'));

function App() {
    return (
        <Suspense fallback={<LoadingSpinner />}>
            <Routes>
                <Route path="/" element={<Home />} />
                <Route path="/dashboard" element={<Dashboard />} />
                <Route path="/analytics" element={<Analytics />} />
            </Routes>
        </Suspense>
    );
}
Pro Tip

Use webpack-bundle-analyzer to visualize your bundle. Look for large dependencies that could be loaded on demand.

Virtualization for Large Lists

Rendering 1000 list items? Only render what's visible. react-window keeps DOM nodes minimal:

List Virtualization
import { FixedSizeList as List } from 'react-window';

function VirtualList({ items }) {
    const Row = ({ index, style }) => (
        <div style={style}>
            {items[index].name}
        </div>
    );
    
    return (
        <List
            height={500}
            itemCount={items.length}
            itemSize={50}
            width="100%"
        >
            {Row}
        </List>
    );
}

// Renders only ~10 DOM nodes instead of 1000!
Common Mistake

Don't virtualize small lists (<50 items). The overhead outweighs benefits. Measure first, optimize second.

State Management Optimization

Where you place state matters. Keep state as close to where it's used as possible:

  1. Local state: useState for component-only data
  2. Lifted state: Common parent for shared sibling data
  3. Context: Truly global, rarely changing data (theme, auth)
  4. External: Redux/Zustand for complex interdependent state

Avoid prop drilling by using composition patterns before reaching for context or Redux.