State management libraries sell certainty, but most apps need far less machinery than they buy. Hooks cover an enormous range gracefully — if you match the tool to the shape of the state instead of reaching for the biggest hammer.
useState for independent values
Form fields, toggles, selected tabs: values that change alone and don't constrain each other belong in their own useState calls. Splitting them keeps renders cheap and code obvious — one variable, one setter, one story.
useReducer for coordinated transitions
When updating one value must update others — wizards, carts, editors — a reducer centralizes the rules. Every transition becomes a named action you can log, test and replay, which pays off the first time a bug report says "it worked until I clicked back."
- Lift state only to the lowest common parent that needs it.
- Share read-mostly data with context; keep updates local.
- Add a library when async caching dominates — not before.
Simple state is a feature: fewer concepts for the next developer, fewer renders for the user, and fewer 2 a.m. mysteries for everyone.
Mateo Alvarado
Web developer & UI/UX designer, Semicolon Studio