state-topologylisted
Install: claude install-skill soumit-kaz/lazysitter
# State topology
Most bad state designs are a **misclassification**, not a bad library choice. Classify first; place second.
## The four kinds
| kind | owned by | lives in | the failure when misplaced |
|---|---|---|---|
| **server state** | the backend | the server-state cache (react-query/SWR/Apollo) | copied into `useState` → goes stale, and nothing tells you |
| **URL state** | the URL | search params / route segments | unlinkable, unshareable, back button does the wrong thing |
| **client state** | this UI | the nearest common consumer | lifted too high → re-renders everything; too low → drilled |
| **session state** | the session | one well-known store | duplicated → theme/locale disagree between screens |
## The single biggest bug source: server state copied into client state
```jsx
const { data } = useQuery(['user', id], fetchUser);
const [user, setUser] = useState(data); // ← a second copy nothing keeps in sync
```
Once copied, the cache can update and the copy will not. Every "it shows the old value until I refresh" bug traces back here.
Legitimate reasons to copy exist — an editable draft of a fetched entity is the main one. When you do, say explicitly **what reconciles them**: when the draft resets, what happens if the server value changes mid-edit, and whether the user is told.
## URL state — decide it early, it is expensive to retrofit
Belongs in the URL: filters, search terms, sort, pagination, selected tab, selected entity id, and often whether