Skip to content
intermediatePhase 36 · React

React Performance

Optimize React apps with memo, lazy loading, code splitting, and profiling.

1h
0 problems
Topic Progress0%

React.memo

React.memo

React.memo prevents unnecessary re-renders by memoizing components.

Basic Usage

const MemoizedComponent = React.memo(function Component({ prop }) {
  console.log("Rendered");
  return <div>{prop}</div>
});

// Only re-renders when props change (shallow comparison)

When It Helps

// Parent re-renders, but Child only re-renders if props change
function Parent() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState("Alice");

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <MemoizedChild name={name} /> // Only re-renders when name changes
    </div>
  );
}

const MemoizedChild = React.memo(function Child({ name }) {
  console.log("Child rendered");
  return <p>{name}</p>;
});

Custom Comparison

const MemoizedComponent = React.memo(
  function Component({ user, onSelect }) {
    return (
      <div onClick={() => onSelect(user.id)}>
        {user.name}
      </div>
    );
  },
  (prevProps, nextProps) => {
    // Custom comparison logic
    return prevProps.user.id === nextProps.user.id;
  }
);

Common Mistakes

// Bad: Inline function creates new reference every render
<Child onClick={() => handleClick(id)} />

// Good: useCallback for stable reference
const handleClick = useCallback((id) => {
  // ...
}, []);
<Child onClick={handleClick} />

// Bad: Object literal creates new reference every render
<Child style={{ color: "red" }} />

// Good: Constant object
const style = { color: "red" };
<Child style={style} />

Code Splitting

Code Splitting

Code splitting loads code only when needed.

React.lazy

import { lazy, Suspense } from "react";

// Lazy load components
const Dashboard = lazy(() => import("./Dashboard"));
const Settings = lazy(() => import("./Settings"));

function App() {
  const [page, setPage] = useState("dashboard");

  return (
    <div>
      <nav>
        <button onClick={() => setPage("dashboard")}>Dashboard</button>
        <button onClick={() => setPage("settings")}>Settings</button>
      </nav>

      <Suspense fallback={<Loading />}>
        {page === "dashboard" && <Dashboard />}
        {page === "settings" && <Settings />}
      </Suspense>
    </div>
  );
}

Route-Based Splitting

import { lazy, Suspense } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";

const Home = lazy(() => import("./pages/Home"));
const About = lazy(() => import("./pages/About"));
const Contact = lazy(() => import("./pages/Contact"));

function App() {
  return (
    <BrowserRouter>
      <Suspense fallback={<Loading />}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/contact" element={<Contact />} />
        </Routes>
      </Suspense>
    </BrowserRouter>
  );
}

Error Boundaries

import { Component } from "react";

class ErrorBoundary extends Component {
  state = { hasError: false };

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

// Usage with lazy loading
<ErrorBoundary>
  <Suspense fallback={<Loading />}>
    <LazyComponent />
  </Suspense>
</ErrorBoundary>

Benefits

  • Smaller initial bundle
  • Faster load time
  • Load on demand
  • Better caching

Profiling

Profiling

React DevTools Profiler

  1. Install React DevTools
  2. Go to Profiler tab
  3. Click Record
  4. Perform actions
  5. Analyze results

What to Look For

  • Unused re-renders: Components re-rendering without changes
  • Slow renders: Components taking too long to render
  • Memory leaks: Components not cleaning up

Performance Patterns

// Bad: Re-renders entire list
function TodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo) => (
        <TodoItem key={todo.id} todo={todo} />
      ))}
    </ul>
  );
}

// Good: Memoize individual items
const TodoItem = React.memo(function TodoItem({ todo }) {
  return <li>{todo.text}</li>;
});

// Good: Virtualize large lists
import { FixedSizeList } from "react-window";

function VirtualizedList({ items }) {
  return (
    <FixedSizeList
      height={500}
      itemCount={items.length}
      itemSize={35}
    >
      {({ index, style }) => (
        <div style={style}>{items[index].name}</div>
      )}
    </FixedSizeList>
  );
}

useMemo and useCallback

// Memoize expensive computations
const sortedItems = useMemo(
  () => [...items].sort((a, b) => a.name.localeCompare(b.name)),
  [items]
);

// Memoize callbacks for memoized children
const handleSelect = useCallback((id) => {
  setSelected(id);
}, []);

// Use with React.memo
const Child = React.memo(({ onSelect }) => ...);
<Child onSelect={handleSelect} />

Bundle Analysis

# Install bundle analyzer
npm install --save-dev webpack-bundle-analyzer

# Analyze bundle
npx webpack-bundle-analyzer stats.json

Performance Checklist

  • Use React.memo for pure components
  • Memoize expensive computations
  • Use useCallback for stable callbacks
  • Code split with React.lazy
  • Virtualize large lists
  • Avoid inline functions in JSX
  • Profile with React DevTools

Practice Problems

0/3solved
Build React Performance Component

Create a reusable React component implementing React Performance. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
React Performance Testing

Write unit and integration tests for React Performance using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
React Performance Performance

Optimize React Performance for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. What does React.memo do?

Question 1 options

2. What is code splitting?

Question 2 options

3. How do you lazy load a component?

Question 3 options

4. What is the purpose of Suspense?

Question 4 options

Flashcards

Question

What does React.memo do?

Answer

Prevents unnecessary re-renders by memoizing components

Question

How do you lazy load a component?

Answer

lazy(() => import('./Component'))

Question

What is code splitting?

Answer

Loading code only when needed to reduce bundle size

Question

What does Suspense do?

Answer

Shows fallback UI while lazy components load

Question

What is React Performance?

Answer

React Performance is a key concept in frontend development.

Revision Notes

Key Takeaways

  • 1.React.memo prevents unnecessary re-renders
  • 2.Code splitting reduces initial bundle size
  • 3.Suspense handles loading states
  • 4.Memoize expensive computations
  • 5.Profile with React DevTools

Interview Tips

  • Explain React.memo and when to use it
  • Show how to implement code splitting
  • Discuss performance optimization strategies

Cheat Sheet

Cheat Sheet

React.memo

const Child = React.memo(({ prop }) => ...);
// Only re-renders when props change

Lazy Loading

const Lazy = lazy(() => import('./Component'));
<Suspense fallback={<Loading />}>
  <Lazy />
</Suspense>

useMemo

const result = useMemo(() => expensive(data), [data]);

useCallback

const fn = useCallback(() => doStuff(a, b), [a, b]);

Performance Tips

  • Use React.memo for pure components
  • Memoize expensive computations
  • Code split with lazy loading
  • Virtualize large lists
  • Avoid inline functions