State Management
Decision Tree
- Can this be derived from existing state? → derived state (no new state needed)
- Is it used by one component? → useState (local state)
- Is it used by a small subtree? → prop drilling (simple case) or useContext
- Is it complex (multi-step, undo/redo)? → useReducer
- Is it used across many unrelated components? → external library (Zustand, Redux, Jotai)
Rules
- Single source of truth for each piece of state
- State should be minimized — derive what you can
- Server state (API data) is different from UI state — use React Query/SWR for server state
- Don't put computed values in state — compute them during render
Patterns
// Good: derive from state
const [items, setItems] = useState<Item[]>([])
const totalPrice = useMemo(() =>
items.reduce((sum, i) => sum + i.price, 0),
[items]
)
// Bad: redundant state
const [items, setItems] = useState<Item[]>([])
const [totalPrice, setTotalPrice] = useState(0) // derived from items!