Memoization reuses a pure function’s previous result when its inputs have not changed. Unlike a cache that may retain many results, it usually retains the latest input and output. In React, it can avoid recalculations and prevent unchanged parts of a UI from rendering again when a parent renders. section 3.2 section 3.2.1
Choose the React tool for the value you need to preserve:
- Wrap a component in `memo()` to reuse its output when its props remain the same. section 3.2.1
- Use `useMemo(calculate, dependencies)` for a calculated value or JSX. React recalculates it when a dependency changes. section 3.2.2 section 3.2.4
- Use `useCallback(callback, dependencies)` to keep a function prop stable between renders when its dependencies remain unchanged. section 3.2.3 section 3.2.4
Keep a to-do list still while typing
A controlled input updates its parent on every keystroke. Without memoization, the sibling item list renders too. Wrapping the item-list component in `memo()` lets it reuse its output while its `items` prop is unchanged; alternatively, `useMemo()` can preserve list JSX inside the parent with `[items]` as its dependencies. The reported inline-JSX example took about 2 ms per typing event with `useMemo()`, versus 3–4 ms without it. section 3.2.1 section 3.2.2
Stable props matter. An inline array or callback is a new value on each parent render, even if its contents or code look identical. Derive the array with `useMemo()` and stabilize a callback with `useCallback()` when passing them to a memoized component. Include dependencies that must trigger an update; avoid adding memoization without a performance reason, because its overhead can outweigh the savings. section 3.2.3 section 3.4
Listing 3.10 A to-do list with deletable items
import { memo, useCallback, useState } from "react";
const Items = memo(function Items({ items, onDelete }) {
return (
<>
<h2>Todo items</h2>
<ul>
{items.map((todo) => (
<li key={todo}>
{todo}
<button onClick={() => onDelete(todo)}>X</button>
</li>
))}
</ul>
</>
);
});
function Todo() {
const [items, setItems] = useState(["Clean gutter", "Do dishes"]);
const [newItem, setNewItem] = useState("");
const onSubmit = (evt) => {
setItems((items) => items.concat([newItem]));
setNewItem("");
evt.preventDefault();
};
const onChange = (evt) => setNewItem(evt.target.value);
const onDelete = useCallback( #1
(item) => setItems((list) => list.filter((i) => i !== item)),
[] #2
);
return (
<main>
<Items items={items} onDelete={onDelete} />
<form onSubmit={onSubmit}>
<input value={newItem} onChange={onChange} />
<button>Add</button>
</form>
</main>
);
}
function App() {
return <Todo />;
}
export default App;
The deletable to-do listing pairs `memo(Items)` with a `useCallback()` delete handler, showing why the child also needs a stable function prop. section 3.2.3
For an expensive derived list, `useMemo()` can filter employees only when the employee array or filter flag changes. In a TypeScript playlist, a shared `useCallback()` handler likewise supports memoized song components; moving that handler out of a loop to obey hook rules requires explicit argument types where prop-context inference is lost. React 19’s experimental Compiler aims to automate memoization, but manual techniques remain relevant. section 3.2.4 section 6.1.6 section 3.2







