Professional React · Lesson 17 of 21
Performance: memo, useMemo and useCallback
When components re-render, and when memoization actually helps.
Rule: when a component re-renders, all its children re-render too, even if their props didn't change. Usually that's fast and fine. But for an expensive child (a long list, a chart) you can prevent it with:
memo(Component): skip re-rendering when props are the same.useMemo(() => calc, deps): remember an expensive calculation's result.useCallback(fn, deps): keep the same function, somemoisn't defeated.
const renders = { list: 0 }
const CourseList = memo(function CourseList({ items, onPick }) {
renders.list++
console.log("CourseList rendered", renders.list, "times")
return <ul>{items.map((c) => <li key={c} onClick={() => onPick(c)}>{c}</li>)}</ul>
})
function App() {
const [query, setQuery] = useState("")
const [clicks, setClicks] = useState(0)
const all = ["HTML", "CSS", "JavaScript", "Python", "React", "SQL", "C++"]
const items = useMemo(() => all.filter((c) => c.toLowerCase().includes(query.toLowerCase())), [query])
const onPick = useCallback((c) => console.log("picked", c), [])
return (
<div>
<input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Filter" />
<button onClick={() => setClicks(clicks + 1)}>Unrelated click ({clicks})</button>
<CourseList items={items} onPick={onPick} />
</div>
)
}Press "Unrelated click" a few times and watch the console: CourseList doesn't re-render because items and onPick are the same values. Remove useMemo or useCallback and every render creates a new array or function, so memo sees different props and re-renders.
App re-renders
Same items and onPick references?
yes → memo skips CourseList
no → CourseList re-renders
Quick question
A memo component receives style={{ color: "red" }} from its parent. Does it re-render when the parent does?
Exercise
expensive is slow. Compute it with useMemo so it depends on n only, not on theme. The page shows Result: 55 and Computed 1 times, even after the checker presses Theme twice.
Result: 55 Computed 1 times Theme
let computed = 0
function expensive(n) {
computed++
let sum = 0
for (let i = 1; i <= n; i++) sum += i
return sum
}
function App() {
const [n] = useState(10)
const [theme, setTheme] = useState("light")
const result = expensive(n)
return (
<div>
<p>Result: {result}</p>
<p>Computed {computed} times</p>
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>Theme</button>
</div>
)
}Learn more from
Played 0 of 2 games
Sign in to save your progress and earn XP.