Frontend state management: picking an approach that fits
Most state management debates argue about which library to use before answering a more basic question: what kind of state is this, actually? That answer usually decides the approach.By MI Technologies Engineering3 min read
Frontend state management discussions tend to jump straight to "which library" — Redux, Zustand, Context, Jotai — before answering a more useful question first: what kind of state is this, actually? Different kinds of state genuinely call for different handling, and most of the pain in badly-managed frontend state comes from treating every kind the same way.
The categories that actually matter
Server state — data that originates from your backend: a list of products, a user's profile, search results. This state is fundamentally about caching, synchronization and staleness, not just storage. Treating it like ordinary local state (fetch it, stuff it in a context, manage loading/error flags by hand everywhere) recreates problems that dedicated data-fetching libraries already solve well — caching, background refetching, deduplicating in-flight requests.
UI state — whether a modal is open, which tab is selected, form input values before submission. This state is local to a component or a small part of the tree, changes frequently, and rarely needs to be shared broadly. Reaching for a global store for state like this adds indirection with no real benefit.
Shared application state — state that genuinely needs to be read and written from multiple, unrelated parts of the component tree: the current authenticated user, a shopping cart, a theme preference. This is the category global state tools are actually built for.
URL state — anything that represents "what the user is currently looking at" and should survive a page refresh or be shareable via a link: a search query, a filter selection, pagination. This belongs in the URL, not in application memory — putting it in a store instead means a refresh or a shared link loses context it should have kept.
Why conflating these causes real problems
The most common state-management pain we see is server state and UI state both being managed through the same mechanism — usually a single global store holding everything. This creates specific, recurring problems: stale server data because nothing is re-fetching it automatically, unnecessary re-renders because UI state changes trigger updates across unrelated parts of the tree, and a growing store that becomes hard to reason about because it mixes concerns that have genuinely different lifecycles.
A practical default
- Server state: a dedicated data-fetching library (React Query, SWR, or equivalent) that handles caching, revalidation and loading/error states — not manually managed in a global store.
- UI state: local component state (
useState) by default. Lift it only as far up the tree as the components that actually need to share it. - Shared application state: a lightweight global store (Context for infrequent updates, a dedicated state library for frequent ones), scoped to genuinely cross-cutting concerns — not everything.
- URL state: the router's own query parameters or path segments, not application state at all.
When this matters most
The cost of getting this wrong scales with application size. A small project with a handful of components can get away with putting everything in one place — the problems this causes are small enough not to matter yet. A growing application accumulates the cost: more re-renders, more stale data bugs, more difficulty reasoning about where a given piece of state actually lives and who can change it.
This is why we design state architecture deliberately at the start of a project with meaningful interactivity, rather than letting it accumulate ad hoc — the migration cost of untangling conflated state later is real, and avoidable with an early decision that costs little to make correctly the first time.
If you are dealing with a frontend that has become hard to reason about because of how its state is organized, tell us about it and we will give you an honest view of what incremental improvement versus a larger restructuring would actually involve.
MI Technologies Engineering
Software engineering team at Mohansh Innovations Pvt. Ltd.