IA
Indra Arianggi
Back to Blog

Optimizing React Performance

5 min read
React Performance Optimization Web Development
Optimizing React Performance

Introduction

Performance optimization is crucial for delivering a great user experience in React applications. This guide covers practical techniques and strategies to improve your React application’s performance, from code splitting to rendering optimizations.

Code Splitting

Dynamic Imports

Use dynamic imports to split your code into smaller chunks:

import { lazy, Suspense } from "react";
 
const HeavyComponent = lazy(() => import("./HeavyComponent"));
 
function App() {
  return (
    <Suspense fallback={<LoadingSpinner />}>
      <HeavyComponent />
    </Suspense>
  );
}

Route-based Code Splitting

Implement code splitting at the route level:

import { lazy } from "react";
 
const Home = lazy(() => import("./pages/Home"));
const Dashboard = lazy(() => import("./pages/Dashboard"));
const Settings = lazy(() => import("./pages/Settings"));
 
const routes = [
  {
    path: "/",
    component: Home,
  },
  {
    path: "/dashboard",
    component: Dashboard,
  },
  {
    path: "/settings",
    component: Settings,
  },
];

Rendering Optimization

React.memo

Prevent unnecessary re-renders with React.memo:

const ExpensiveComponent = React.memo(({ data }) => {
  // Complex rendering logic
  return (
    <div>
      {data.map((item) => (
        <Item key={item.id} {...item} />
      ))}
    </div>
  );
});

useMemo and useCallback

Cache expensive computations and callbacks:

function SearchResults({ items, query }) {
  // Cache filtered results
  const filteredItems = useMemo(() => {
    return items.filter((item) =>
      item.name.toLowerCase().includes(query.toLowerCase())
    );
  }, [items, query]);
 
  // Cache callback
  const handleItemClick = useCallback((id) => {
    console.log(`Item clicked: ${id}`);
  }, []);
 
  return (
    <ul>
      {filteredItems.map((item) => (
        <ListItem key={item.id} item={item} onClick={handleItemClick} />
      ))}
    </ul>
  );
}

State Management Optimization

State Colocation

Keep state as close as possible to where it’s used:

// Bad: State too high in the tree
function ParentComponent() {
  const [isOpen, setIsOpen] = useState(false);
  return (
    <div>
      <OtherComponent />
      <ModalComponent isOpen={isOpen} setIsOpen={setIsOpen} />
    </div>
  );
}
 
// Good: State colocated with usage
function ModalComponent() {
  const [isOpen, setIsOpen] = useState(false);
  return (
    <div>
      <button onClick={() => setIsOpen(true)}>Open Modal</button>
      {isOpen && <Modal onClose={() => setIsOpen(false)} />}
    </div>
  );
}

Context Optimization

Split contexts to prevent unnecessary re-renders:

// Split theme and user contexts
const ThemeContext = React.createContext(null);
const UserContext = React.createContext(null);
 
function App() {
  const [theme, setTheme] = useState("light");
  const [user, setUser] = useState(null);
 
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <UserContext.Provider value={{ user, setUser }}>
        <MainContent />
      </UserContext.Provider>
    </ThemeContext.Provider>
  );
}

Virtual List

Implement virtual scrolling for long lists:

import { FixedSizeList } from "react-window";
 
function VirtualList({ items }) {
  const Row = ({ index, style }) => (
    <div style={style}>
      <ListItem data={items[index]} />
    </div>
  );
 
  return (
    <FixedSizeList
      height={400}
      width={300}
      itemCount={items.length}
      itemSize={50}
    >
      {Row}
    </FixedSizeList>
  );
}

Image Optimization

Lazy Loading Images

Use lazy loading for images below the fold:

function ImageGallery({ images }) {
  return (
    <div>
      {images.map((image) => (
        <img key={image.id} src={image.url} loading="lazy" alt={image.alt} />
      ))}
    </div>
  );
}

Performance Monitoring

React DevTools Profiler

Use the React DevTools Profiler to identify performance bottlenecks:

import { Profiler } from "react";
 
function onRenderCallback(
  id,
  phase,
  actualDuration,
  baseDuration,
  startTime,
  commitTime
) {
  console.log(`Component ${id} took ${actualDuration}ms to render`);
}
 
function App() {
  return (
    <Profiler id="App" onRender={onRenderCallback}>
      <MainContent />
    </Profiler>
  );
}

Conclusion

Performance optimization in React is an ongoing process that requires careful consideration of component structure, state management, and resource loading. By implementing these techniques strategically, you can significantly improve your application’s performance and user experience.

Remember to:

  • Measure before optimizing
  • Focus on the most impactful optimizations first
  • Test performance improvements across different devices and network conditions
  • Monitor performance metrics in production
Indra Arianggi

Indra Arianggi