JavaScript Curriculum
Performance — memo & callbacks
mediumThe coffee shop menu renders 200 items. Every cart update causes all 200 MenuCards to re-render — even though none of their props changed. React.memo plus useCallback solves this with a few lines.
Performance — memo & callbacks
React is fast by default. Memoisation tools help you skip unnecessary re-renders — but only apply them after profiling confirms there is a measurable problem.
React.memo — Skip Component Re-renders
See exactly which components re-render with and without memo:
// ✓ React.memo — skips re-render if props unchanged const MenuCard = memo(function MenuCard({ name, price }) { return <div>{name} — £{price.toFixed(2)}</div> }) // MenuCard won't re-render when count or text changes // Only re-renders when name or price props change
useCallback — Stable Function References
Without useCallback, every render creates a new function — breaking React.memo:
// ✓ With useCallback — stable function reference function App() { const [cart, setCart] = useState([]) // Stable reference — only changes if deps change: const handleOrder = useCallback( (id) => setCart(c => [...c, id]), [] // no deps — stable for component lifetime ) // React.memo works correctly now: return <MenuCard onOrder={handleOrder} /> }
When to Use Each — and When Not To
React.memo, useMemo, useCallback — the right tool for each job:
// React is fast by default — DON'T optimise prematurely // Profile FIRST, then optimise: // 1. Use React DevTools Profiler to find slow components // 2. Check if unnecessary re-renders cause measurable lag // 3. Only then reach for memo/useMemo/useCallback // The cost of premature optimisation: // - memo: adds comparison cost on every render // - useMemo/useCallback: adds closure allocation cost // For most components, the overhead > the savings // Good candidates for optimisation: // ✓ Long lists (50+ items) with expensive renders // ✓ Heavy computations (chart data, search filtering) // ✓ Components that receive callback props from parents // ✓ Components that show in profiler as hot spots // Bad candidates: // ✗ Simple components that render fast anyway // ✗ Components that almost always re-render on prop changes // ✗ Top-level components (they rarely cause the problem)
Your Challenge
Build a list of 50 MenuCard items. Add a text input whose state change causes the parent to re-render. Without memo: all 50 cards re-render on each keystroke. Add React.memo to MenuCard and useCallback to the onOrder handler — verify only the parent re-renders on keystroke.
Challenge
Wrap a MenuCard in React.memo. Stabilise its onOrder callback with useCallback in the parent. Measure: without these, how many renders happen on a cart update? With them, how many? Use the render counter pattern to count.
Performance — memo & callbacks
mediumThe coffee shop menu renders 200 items. Every cart update causes all 200 MenuCards to re-render — even though none of their props changed. React.memo plus useCallback solves this with a few lines.
Performance — memo & callbacks
React is fast by default. Memoisation tools help you skip unnecessary re-renders — but only apply them after profiling confirms there is a measurable problem.
React.memo — Skip Component Re-renders
See exactly which components re-render with and without memo:
// ✓ React.memo — skips re-render if props unchanged const MenuCard = memo(function MenuCard({ name, price }) { return <div>{name} — £{price.toFixed(2)}</div> }) // MenuCard won't re-render when count or text changes // Only re-renders when name or price props change
useCallback — Stable Function References
Without useCallback, every render creates a new function — breaking React.memo:
// ✓ With useCallback — stable function reference function App() { const [cart, setCart] = useState([]) // Stable reference — only changes if deps change: const handleOrder = useCallback( (id) => setCart(c => [...c, id]), [] // no deps — stable for component lifetime ) // React.memo works correctly now: return <MenuCard onOrder={handleOrder} /> }
When to Use Each — and When Not To
React.memo, useMemo, useCallback — the right tool for each job:
// React is fast by default — DON'T optimise prematurely // Profile FIRST, then optimise: // 1. Use React DevTools Profiler to find slow components // 2. Check if unnecessary re-renders cause measurable lag // 3. Only then reach for memo/useMemo/useCallback // The cost of premature optimisation: // - memo: adds comparison cost on every render // - useMemo/useCallback: adds closure allocation cost // For most components, the overhead > the savings // Good candidates for optimisation: // ✓ Long lists (50+ items) with expensive renders // ✓ Heavy computations (chart data, search filtering) // ✓ Components that receive callback props from parents // ✓ Components that show in profiler as hot spots // Bad candidates: // ✗ Simple components that render fast anyway // ✗ Components that almost always re-render on prop changes // ✗ Top-level components (they rarely cause the problem)
Your Challenge
Build a list of 50 MenuCard items. Add a text input whose state change causes the parent to re-render. Without memo: all 50 cards re-render on each keystroke. Add React.memo to MenuCard and useCallback to the onOrder handler — verify only the parent re-renders on keystroke.
Challenge
Wrap a MenuCard in React.memo. Stabilise its onOrder callback with useCallback in the parent. Measure: without these, how many renders happen on a cart update? With them, how many? Use the render counter pattern to count.