Skip to content
Go back

You probably don't need a state management library

Published:  at  02:00 PM

Most React apps I audit reach for a global store before they have a problem it solves. Redux gets installed on day one, out of habit, and then half the app’s state is routed through it for no reason. Before you add a store, it is worth asking what state you actually have.

The habit

Somewhere along the way, “React app” started to imply “React plus a state library.” So the store goes in first, and every new piece of data gets pushed into it because that is where data goes now. The app ends up with a giant global object holding things that only one component ever reads.

That is not a store solving a problem. That is a store creating one.

What you are actually storing

Most of what people put in a global store falls into a few buckets.

Only that last bucket wants a global store. The first belongs in the component. The second belongs somewhere else entirely.

Server state is not app state

The biggest chunk of what ends up in Redux is data that came from an API. That data has caching, refetching, staleness, and loading states as real concerns. A general purpose store handles none of that for you, so you hand-write it, badly.

A server-state library (React Query, or SWR) already solves caching, background refetch, and stale handling. Move your fetched data there and a huge share of your “global state” disappears. What is left is small.

When a store earns its place

There is a real line. You want a dedicated client store when you have state that is truly global, changes often, and is read by many unrelated parts of the tree. A complex cart, a collaborative editor’s local document, a multi-step wizard whose steps live far apart.

At that point a store is the right tool. Add it then, when the pain is concrete, not on day one as insurance.

The lighter path

Even when you do want shared client state, the library does not have to be heavy. On smaller apps I reach for Preact with signals. A signal is a single reactive value you read anywhere and update anywhere, with no reducers, no actions, no provider tree wrapping your whole app.

The rule I follow: local state until it hurts, server-state library for anything fetched, and a real store only for the slice that is genuinely global. Add the weight when you feel the need for it, not before.



Previous Post
Deploying a static site to S3 and Cloudflare with GitHub Actions
Next Post
NestJS or plain Node: when the framework earns its weight