Lesson 17 of 20

Performance Optimization

Avoiding Unnecessary Re-Renders

React re-renders a component whenever its state or props change. In most cases this is fast enough, but for large lists or expensive computations, unnecessary re-renders can cause performance issues.

React provides React.memo, useMemo, and useCallback to optimize performance by preventing unnecessary work.

Example
import { useState, useMemo, useCallback, memo } from 'react';

// React.memo — Prevents re-render if props haven't changed
const ExpensiveItem = memo(function ExpensiveItem({ item, onSelect }) {
  console.log('Rendering:', item.name);
  return (
    <div onClick={() => onSelect(item.id)}>
      {item.name}
    </div>
  );
});

function ItemList({ items }) {
  const [filter, setFilter] = useState('');
  const [selectedId, setSelectedId] = useState(null);

  // useMemo — Cache expensive computation
  const filteredItems = useMemo(() => {
    return items.filter(item =>
      item.name.toLowerCase().includes(filter.toLowerCase())
    );
  }, [items, filter]);

  // useCallback — Cache function reference
  const handleSelect = useCallback((id) => {
    setSelectedId(id);
  }, []);

  return (
    <div>
      <input value={filter} onChange={e => setFilter(e.target.value)} />
      {filteredItems.map(item => (
        <ExpensiveItem
          key={item.id}
          item={item}
          onSelect={handleSelect}
        />
      ))}
    </div>
  );
}
  • React.memo(Component) — Skips re-render if props are the same
  • useMemo(fn, [deps]) — Caches the result of an expensive computation
  • useCallback(fn, [deps]) — Caches a function reference
  • Don't optimize prematurely — measure first, optimize when needed
  • Use React DevTools Profiler to identify performance bottlenecks
Notes
  • React is fast by default. Only add memo, useMemo, or useCallback when you identify actual performance issues. Premature optimization adds complexity without benefit.