📖 Notes LESSON 14 OF 18

React.memo, useMemo & useCallback

⏱️ 25 min
⚛️ React

Skipping Renders That Don't Need to Happen

React.memo, useMemo, and useCallback all exist to avoid unnecessary re-renders and recalculations — but they're an optimisation for a real performance problem, not something to add everywhere by default.

memo, useMemo, useCallback

🧊
React.memo(Component)
Skips re-rendering a component if its props haven't changed.
🧮
useMemo(fn, [deps])
Caches an expensive calculation, only recomputing when dependencies change.
📎
useCallback(fn, [deps])
Caches a function reference so it doesn't cause unnecessary child re-renders.
⚠️
Warning
Overusing these adds complexity for little benefit — profile first, optimise second.
Memoized Dashboard
JSX
import { memo, useMemo, useCallback } from "react";

// memo — skip re-render if props unchanged
const CourseCard = memo(function CourseCard({ title, lessons }) {
  return <div>{title} · {lessons} lessons</div>;
});

function Dashboard({ courses, filter }) {
  // Cache expensive computation
  const filtered = useMemo(
    () => courses.filter(c => c.cat === filter),
    [courses, filter]
  );

  // Stable function reference
  const handleEnroll = useCallback((id) => {
    enrollAPI(id);
  }, []);

  return filtered.map(c => <CourseCard key={c.id} {...c} onEnroll={handleEnroll} />);
}
⚠️
Profile first, optimise second
Adding memo/useMemo/useCallback everywhere adds complexity without necessarily improving performance. Use React DevTools Profiler to find actual re-render problems before reaching for these tools.
🗒 Cheat Sheet 📝 Worksheet