Back to Blog
Guide7 min read2026-05-01

React Performance Optimization: Tips and Techniques

A practical guide to React performance optimization covering memoization, code splitting, virtual DOM efficiency, and more.

React Performance Optimization: Tips and Techniques

React is fast by default for most applications. But as component trees grow, as data fetching becomes more complex, and as UI interactions multiply, performance issues creep in. The good news: React gives you precise tools to address each type of problem. This guide covers the most impactful techniques with practical examples.

Profile Before Optimizing

The single most important rule: measure first. React DevTools Profiler shows you exactly which components re-render and why. Install it as a browser extension and use the Profiler tab to record interactions before making any changes.

Common problems it reveals:

  • Components re-rendering when their props have not changed
  • Large component trees re-rendering due to a state update deep in one branch
  • Expensive calculations running on every render

Prevent Unnecessary Re-Renders with React.memo

By default, React re-renders a component whenever its parent re-renders — even if the component's props have not changed. React.memo prevents this with a shallow prop comparison.

// Without memo: re-renders every time parent renders
function ProjectCard({ project }) {
  return <div>{project.name}</div>;
}

// With memo: only re-renders when project prop changes
const ProjectCard = React.memo(function ProjectCard({ project }) {
  return <div>{project.name}</div>;
});

Only apply React.memo to components that are genuinely expensive to render and receive stable props. Adding it everywhere is not free — the comparison itself has a cost.

Memoize Expensive Calculations with useMemo

useMemo caches the result of a calculation between renders, recomputing only when its dependencies change.

function Dashboard({ deployments }) {
  // Without useMemo: recalculates on every render
  // With useMemo: recalculates only when `deployments` changes
  const stats = useMemo(() => ({
    total: deployments.length,
    running: deployments.filter(d => d.status === 'RUNNING').length,
    failed: deployments.filter(d => d.status === 'FAILED').length,
  }), [deployments]);

  return <StatsBar stats={stats} />;
}

Stabilize Callbacks with useCallback

Functions defined inside a component are recreated on every render. When passed as props, this causes child components (even memoized ones) to re-render unnecessarily. useCallback returns a stable function reference.

function ProjectList({ onDelete }) {
  // onDelete is stable — ProjectCard won't re-render when parent does
  const handleDelete = useCallback((id) => {
    onDelete(id);
  }, [onDelete]);

  return projects.map(p => (
    <ProjectCard key={p.id} project={p} onDelete={handleDelete} />
  ));
}

Code Splitting with React.lazy

Do not ship your entire application on the initial load. Split large routes into separate bundles that load on demand.

import React, { Suspense } from 'react';
const Dashboard = React.lazy(() => import('./views/Dashboard'));
const Settings = React.lazy(() => import('./views/Settings'));
const Monitoring = React.lazy(() => import('./views/Monitoring'));

function App() {
  return (
    <Suspense fallback={<PageLoader />}>
      <Routes>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/settings" element={<Settings />} />
        <Route path="/monitoring" element={<Monitoring />} />
      </Routes>
    </Suspense>
  );
}

This keeps the initial bundle small and only loads each view when the user navigates to it.

Virtualize Long Lists

Rendering 1,000 DOM nodes at once is slow regardless of how optimized your components are. Use windowing/virtualization to render only the visible rows.

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

function DeploymentLog({ entries }) {
  return (
    <List
      height={600}
      itemCount={entries.length}
      itemSize={40}
      width="100%"
    >
      {({ index, style }) => (
        <div style={style}>{entries[index].message}</div>
      )}
    </List>
  );
}

react-window renders only the items in the viewport, making lists of thousands of items feel instant.

Optimize Context Usage

React Context re-renders every consumer when the context value changes. Avoid putting frequently changing state (like real-time metrics) in a context that also provides stable configuration values.

// Bad: one big context causes all consumers to re-render on any change
const AppContext = React.createContext({ user, theme, notifications, metrics });

// Better: split into multiple contexts with different update frequencies
const UserContext = React.createContext(user);       // rarely changes
const MetricsContext = React.createContext(metrics); // changes often

Image and Asset Optimization

  • Use loading="lazy" on images below the fold
  • Set explicit width and height to prevent layout shift (CLS)
  • Use WebP or AVIF formats
  • Preload critical above-the-fold images with

Deploy a Static React Build

Building your React app for production (npm run build) generates minified, tree-shaken bundles with content hashes. Deploy the resulting /build directory as a static site — no server required for the frontend itself.

[PandaStack](https://dashboard.pandastack.io) supports static site deployments, so you can host your React build with minimal configuration and get the benefit of a CDN-backed delivery layer for all your static assets.

Summary

TechniqueProblem It Solves
React.memoPrevents re-renders when props unchanged
useMemoAvoids expensive recalculations
useCallbackStabilizes function references
React.lazyReduces initial bundle size
react-windowMakes long lists fast
Split ContextLimits context re-render blast radius

Start with the Profiler, identify your actual bottleneck, then apply the technique that addresses it. Premature optimization wastes time; targeted optimization has enormous impact.

Ready to deploy?

Start free on PandaStack — no credit card required.

Start free on PandaStack

More in Guide

Browse all Guide articles →

See also