If You Can Compute It, Don't Store It
Derived State
Anything you can compute from existing state or props shouldn't live in its own state slot. Derive on every render — it's cheap and impossible to get out of sync.
What you'll learn
- Recognize derived values
- Avoid duplicated state
- Know when memoization (`useMemo`) is worth it
A common newcomer mistake: storing every value in state, including ones that could be computed from other state. The result is a UI that’s easy to make inconsistent.
Rule: if you can compute it from state or props, don’t store it — derive it during render.
The Mistake
// ✗ Storing both the items AND the count
function Cart() {
const [items, setItems] = useState([]);
const [count, setCount] = useState(0);
function add(item) {
setItems([...items, item]);
setCount(count + 1); // easy to forget, easy to drift
}
return <p>{count} items</p>;
} count is just items.length. Storing it separately means every
mutation has to update both — and if one path forgets, the UI
lies.
The Fix
// ✓ Derive on every render
function Cart() {
const [items, setItems] = useState([]);
const count = items.length;
function add(item) {
setItems([...items, item]);
}
return <p>{count} items</p>;
} count is always in sync. There’s nothing to forget.
Derived Filter / Sort / Search
function Todos() {
const [todos, setTodos] = useState([]);
const [query, setQuery] = useState("");
// derived, not state
const visible = todos.filter(t =>
t.text.toLowerCase().includes(query.toLowerCase())
);
return (
<>
<input value={query} onChange={e => setQuery(e.target.value)} />
<ul>{visible.map(t => <li key={t.id}>{t.text}</li>)}</ul>
</>
);
} visible is recomputed every render — usually negligible.
When Memoization Helps
If the derivation is genuinely expensive (heavy parsing, large
data) AND the inputs don’t change every render, wrap it in
useMemo:
const sorted = useMemo(
() => items.sort((a, b) => a.priority - b.priority),
[items]
); For everyday filtering of small arrays, don’t bother. useMemo has
its own overhead.
Quick Test
Ask: “Could a user action change state in a way that makes this field wrong?” If yes, it’s derived — compute it instead of storing it.
| Always derive (don’t store) | Almost always store |
|---|---|
| Item count, totals, averages | User input values |
| Filtered/sorted lists | Toggles (open/closed) |
isValid from form fields | Loaded data from the server |
| Full name from first + last | Selected item id |
Up Next
When two components need the same state, move it to a common parent. That’s lifting state up.
Lifting State →