Where state lives
Most confusing bugs are really "two copies of the truth".
State is just "the data your app currently holds". The trouble starts when the same fact exists in two places and they disagree.
The rule
One source of truth for each fact. Everything else derives from it.
If a user's name is in a variable, in a form field, and in a cache, you have three names. They'll agree until they don't, and the resulting bug is deeply confusing because everything looks right somewhere.
Derive, don't duplicate
If you have a list of items and you also store the count, you have two facts that can disagree. The count is derivable — calculate it when you need it.
The same applies to filtered lists, totals, "is anything selected", and formatted versions of values. Store the minimum; compute the rest. Most state bugs are a derived value that got out of sync.
Where to put it
Local to a component — most things. A dropdown's open state doesn't belong anywhere else.
Lifted to a shared parent — when two components need the same fact.
Global — genuinely app-wide things: the current user, the theme. Global state is convenient and makes things harder to reason about, so use it sparingly.
In the URL — this one is underused. Filters, search terms, the current tab, the selected item. Putting it in the URL means the page is shareable, bookmarkable, and the back button works. Users expect all three.
On the server — anything that must be true for other people, or that the client shouldn't be trusted about.
Server data isn't really state
Data fetched from a server is a cache of something that lives elsewhere. It can be stale, it needs refreshing, and treating it like local state is what causes the "I updated it but it still shows the old value" bug.
Here's my app: <paste> Map where each piece of state lives. Then find the problems: - The same fact stored in more than one place. - Values that are derived but stored — a count, a total, a filtered list — and could get out of sync. - Things in memory that should be in the URL, so refreshing and sharing work. - Server data being treated as if it were local state. For each, the fix, and what bug it prevents.
Before adding a state library, check whether your problem is actually duplicated state. Most "I need better state management" is really "I have three copies of this".