Runnable lesson · press Try it on the examples to edit and run them here.
Derived state is a value you can work out from other state or props. The most important rule about it is a short one: do not store it. Calculate it while rendering.
The problem with duplicated state
Here is a shopping list that keeps a separate count in state:
function App() {
const [items, setItems] = React.useState(["Milk", "Eggs"]);
const [count, setCount] = React.useState(2); // duplicated information
return (
<div>
<p>Items: {items.length} (count says {count})</p>
<button onClick={() => setItems([...items, "Bread"])}>Add item</button>
{/* We forgot to call setCount. Now the two disagree. */}
</div>
);
}
After clicking, the list has three items, but count still says 2. Two sources of truth will drift apart the moment you forget to update one of them. Every extra piece of state is something you must keep in sync.
The fix: derive it
function App() {
const [items, setItems] = React.useState(["Milk", "Eggs"]);
const count = items.length; // calculated on each render, always correct
return (
<div>
<p>Items: {count}</p>
<button onClick={() => setItems([...items, "Bread"])}>Add item</button>
</div>
);
}
Now there is one source of truth. The component re-renders whenever items changes, and count is recalculated from the new value for free.
Common derived values
Most of these should never be state:
- Counts, totals, averages:
items.reduce((sum, i) => sum + i.price, 0) - Filtered or sorted lists: see Filtering and Sorting Lists
- Whether a form is valid:
name.length > 0 && email.includes("@") - A full name from first and last, built with a template literal such as
${first} ${last} - A label from a boolean:
open ? "Close" : "Open"
function App() {
const catalog = { Pen: 2.5, Book: 15 };
const [cart, setCart] = React.useState([]);
const total = cart.reduce((sum, name) => sum + catalog[name], 0);
const itemWord = cart.length === 1 ? "item" : "items";
return (
<div>
{Object.keys(catalog).map((name) => (
<button key={name} onClick={() => setCart([...cart, name])}>Add {name}</button>
))}
<p>Total: ${total.toFixed(2)}</p>
<p>{cart.length} {itemWord}</p>
</div>
);
}
The prop-mirroring trap
Copying a prop into state looks harmless, but it freezes the value:
function Price({ amount }) {
const [price, setPrice] = useState(amount); // WRONG: ignores later changes to amount
return <p>{price}</p>;
}
The first value is used, and later changes to amount are ignored. Use the prop directly. If you need an editable copy that starts from the prop, name it initialAmount so everyone knows it is only the starting value, as in Props Are Read-Only.
Expensive calculations
If a derived value takes a long time to compute and its inputs rarely change, you can remember the result with useMemo; see useMemo. Do it only after you have measured a real slowdown. Calculating in render is cheap for most data.
Resetting state when something changes
Sometimes you want state to restart when a prop changes (for example, an edit form when the selected user changes). Do not copy props into state and sync with an effect. Give the component a key, so React makes a new one:
<EditForm key={user.id} user={user} />
A test question
For any piece of state ask: “Can I calculate this from other state or props?” If yes, it should not be state.
Key points
- Derived values are calculated during rendering, not stored in state.
- Duplicate state goes out of sync; one source of truth cannot.
- Do not copy props into state; use the prop, or reset with
key.