React · Lesson 9 of 15
Performance: memo, useMemo and useCallback
Skip wasted renders and expensive work without premature optimisation.
- Intermediate
- 16 min read
- 3 objectives
Before this lessonLesson 8: useReducer and Complex State
What you will learn
- Memoize a component
- Use useMemo and useCallback
- Profile before you cache
Your Progress
0 of 15 lessons 0%
- Lessons0 / 15
- Completed0
- Est. time left~ 4 hours
Create a free account to keep your progress on every device.
React is fast enough for most UIs. Performance work starts when a profiler shows a real problem: a slow list, a laggy input, a child that re-renders for no reason. The tools are memo, useMemo and useCallback.
Skip a render with memo
A child re-renders whenever its parent does, even if its props did not change. Wrap it in memo so React compares props and skips the work when they are equal.
import { memo } from "react";
const UserRow = memo(function UserRow({ user }) {
return <li>{user.name}</li>;
});This only helps if the user reference is stable. Passing a new object or inline function every render defeats memo.
useMemo and useCallback
useMemo caches an expensive calculation. useCallback caches a function so children wrapped in memo see the same prop.
function Directory({ users, query }) {
const visible = useMemo(
() => users.filter((u) => u.name.toLowerCase().includes(query.toLowerCase())),
[users, query],
);
const onSelect = useCallback((id) => console.log(id), []);
return visible.map((u) => <UserRow key={u.id} user={u} onSelect={onSelect} />);
}Lists first
- Give list items a stable
key(the id, never the index if items can move). - Window long lists (react-window) instead of rendering 10,000 rows.
- Do not put a new
style={{}}oronClick={() => ...}on every row if you then wrap the row inmemo.
