React State Management
Esta página aún no está disponible en tu idioma.
State Management in React: A Complete Comparison of the Main Options (and When to Use Each One).
Section titled “State Management in React: A Complete Comparison of the Main Options (and When to Use Each One).”If you’re reading this, you’ve been working with React for a while and at some point in your developer life you’ve had to decide which library or pattern to use to manage your application’s state. Or maybe you’re just getting started and you’ve already seen the names Redux, Zustand, Context API, Jotai, or Recoil floating around without really understanding which one to pick or what each one is actually for.
This post is not going to be an ad for any of them. What you’ll get here is an honest, experience-based look at what state management is, the philosophy behind each option, their advantages, their drawbacks, and when it makes sense to use them and when it doesn’t.
Fair warning: this post is going to be long, but it’s worth reading all the way through.
What Is State Management and Why Does It Matter?
Section titled “What Is State Management and Why Does It Matter?”Before talking about libraries, we need to understand the problem they solve.
In React, state is simply the information that determines how a component renders at any given moment. A basic useState is already state management. The problem comes when that state needs to be shared between components that don’t have a direct relationship in the component tree, or when the business logic becomes complex enough that keeping it inside the components themselves turns into a mess.
Let’s say we have the user’s authentication state. The header needs it to show the avatar, the sidebar needs it to display the right menu based on permissions, and a thousand other components throughout the app need it too. What do we do? The first instinct is usually to lift the state up to the nearest common parent what’s known as prop drilling. It works, but it scales terribly. The fifth level of components receiving props they don’t even use just to pass them down to the sixth level is a maintenance nightmare.
This is where state management libraries come in, each proposing a different solution to the same problem: making data accessible from anywhere in the application in a predictable and efficient way.
Three criteria for choosing a state management solution:
- Application scale: a landing page with a shopping cart is not the same thing as a SaaS platform with dozens of features.
- State complexity: do you have a lot of async logic? Data that depends on other data? Complex data flows?
- Team: a highly opinionated solution like Redux can be perfect if the team knows it well, but a complete nightmare if nobody knows what a
reduceris.
With that said, let’s get into it.
Context API: The Native React Solution.
Section titled “Context API: The Native React Solution.”What Is It?
Section titled “What Is It?”Context API is not an external library, it’s a feature built into React since version 16.3. Its purpose is to pass data through the component tree without needing prop drilling. It works through a Provider that wraps the part of the tree that needs access to the data, and a Consumer (or the useContext hook) to read it.
Philosophy
Section titled “Philosophy”The philosophy behind Context API is simple: it’s a data distribution tool, not a state management tool. This distinction is important and a lot of people miss it. Context API has no opinion about how you handle your data, it just distributes it. To have real state management, you typically combine it with useReducer or useState.
How Does It Work in Practice?
Section titled “How Does It Work in Practice?”You create a context, wrap it with its Provider, and any child component can read the value via useContext. If you combine this with useReducer, you can end up with something that closely resembles a mini-Redux without installing anything.
Advantages
Section titled “Advantages”- Zero external dependencies. It comes with React, there’s nothing to install.
- Simple to understand for teams with little experience with state libraries.
- Perfect for static or low-frequency global data: theme (dark/light mode), language, authenticated user data.
Disadvantages
Section titled “Disadvantages”- Performance: this is the most critical point. Every time the context value changes, all components that consume it re-render, regardless of whether the specific data they use has changed or not. For data that changes rarely, it’s fine. For data that changes constantly (a counter updating every second, for example), it’s a performance disaster.
- No native debugging tools comparable to Redux DevTools.
- Doesn’t scale well for complex state. As the application grows, you have to create multiple contexts and the management becomes cumbersome.
When to Use It?
Section titled “When to Use It?”Use it for simple global state that changes infrequently. Theme configuration, app language, logged-in user data that loads once. If your data changes often or is shared by many components across different parts of the app, look for another option.
Redux: The Veteran of State Management.
Section titled “Redux: The Veteran of State Management.”What Is It?
Section titled “What Is It?”Redux is the oldest and most widely used state management library in the React ecosystem. Today, it’s almost always used in combination with Redux Toolkit (RTK), which drastically reduces the boilerplate that was historically its biggest criticism.
Philosophy
Section titled “Philosophy”Redux’s philosophy is strict and very opinionated:
- A single store. The entire application state lives in one object tree. There’s no negotiation here, as it’s a fundamental principle.
- Read-only state. The state is never mutated directly. It can only change through dispatched actions.
- Changes through pure functions (reducers). Given the same state and the same action, a reducer will always return the same result. No side effects, no surprises.
This model makes the data flow completely predictable and traceable, which is its greatest strength in large applications.
The Ecosystem: Redux Toolkit + Redux Saga
Section titled “The Ecosystem: Redux Toolkit + Redux Saga”Redux on its own is powerful but verbose. Redux Toolkit (RTK) is the official package that modernizes the experience, reducing boilerplate with abstractions like createSlice and createAsyncThunk. For handling complex side effects (requests, elaborate async flows, cancellations, etc.), Redux Saga enters as middleware.
This full stack is, in my opinion, the most powerful in the ecosystem but also the one with the steepest learning curve.
Advantages
Section titled “Advantages”- Scalability: the most robust option for large applications with many developers.
- Exceptional debugging: Redux DevTools enables time travel debugging, letting you see every dispatched action, the state before and after, and replay entire flows.
- Total predictability: the unidirectional flow makes bugs easy to trace.
- Mature ecosystem: documentation, community, established patterns, integrations.
- Redux Saga: lets you handle very complex async flows in an organized and testable way.
Disadvantages
Section titled “Disadvantages”- Boilerplate: even with RTK, generating a new
slice, its actions, its selectors, its saga… is a lot more code than any other alternative. - Learning curve: concepts like reducers, middleware, saga effects, generators… are not trivial.
- Can be overkill for small or medium applications. Using a sledgehammer to crack a nut.
When to Use It?
Section titled “When to Use It?”When you have a large application with many data flows, complex async logic, multiple developers working in parallel, and a need to keep the code scalable and predictable over the long term. If you’re building your startup’s MVP, you probably don’t need it yet.
Zustand: The Opposite Philosophy to Redux.
Section titled “Zustand: The Opposite Philosophy to Redux.”What Is It?
Section titled “What Is It?”Zustand (which means “state” in German) is a minimalist library created by the same authors behind Jotai and React Spring. It’s lightweight, unopinionated, and has gained enormous popularity in recent years for one simple reason: it’s incredibly easy to use.
Philosophy
Section titled “Philosophy”This is where Zustand and Redux are practically opposites. If Redux says “one store to rule them all”, Zustand says “create as many stores as you need: small, focused, and autonomous”.
The idea is simple: each store is a hook. You define the state and the actions that modify it inside a create call, and that hook is consumed directly in any component. No providers, no dispatchers, no reducers. No ceremony.
There’s no forced unidirectional flow, no strictly imposed immutability (though it can be used with Immer). State mutation happens directly inside the store’s own functions. This might sound like heresy after reading the Redux section, but in practice it’s very comfortable and safe when stores are small and well-scoped.
Advantages
Section titled “Advantages”- Minimal boilerplate: creating a working store takes minutes, not hours.
- No Provider: there’s nothing to wrap the application in. Stores are accessible from any component directly.
- Excellent performance: components only re-render when the slice of state they use changes, not when anything in the store changes.
- Composable: you can have many small stores and combine them when needed.
- Compatible with Redux DevTools: yes, you can use Redux DevTools with Zustand, which is a big point in its favor.
Disadvantages
Section titled “Disadvantages”- No enforced structure: flexibility is a double-edged sword. In large teams, without clear conventions, stores can become chaotic.
- Less structured async logic: it doesn’t have a middleware system as robust as Redux Saga for complex flows.
- Less powerful debugging: although compatible with DevTools, the experience isn’t as complete as with Redux.
When to Use It?
Section titled “When to Use It?”Zustand is perfect for medium-sized applications, projects where development speed matters, and small-to-medium teams that don’t want to take on Redux’s complexity. It’s also a great option when migrating from Context API and wanting something more powerful without the Redux overhead.
Jotai: Atomic State.
Section titled “Jotai: Atomic State.”What Is It?
Section titled “What Is It?”Jotai (which means “state” in Japanese) is a library based on the atomic state model, inspired by Facebook’s Recoil. Its fundamental unit is not a store, not a context, it’s an atom: a minimal, independent piece of state.
Philosophy
Section titled “Philosophy”Jotai’s philosophy is granularity. Instead of thinking of “application state” as a monolithic block (Redux) or as focused stores (Zustand), Jotai proposes thinking of state as individual atoms that components can subscribe to, re-rendering only when that specific atom changes.
Atoms can derive from other atoms (derived atoms), letting you build a reactive dependency chain in a declarative way. It’s a model very similar to how reactivity works in Vue or Solid.js, and it feels very natural for certain types of problems.
Additionally, Jotai is deeply integrated with React’s Suspense model and concurrency features, making it very well-prepared for the future of the ecosystem.
Advantages
Section titled “Advantages”- Extreme granularity: minimal and precise re-renders. Only exactly what changes gets updated.
- Very simple API:
atomto create state,useAtomto consume it. As simple asuseStatebut global. - Derived atoms: very powerful for computing derived state from other atoms without repeating logic.
- Suspense integration: for reactive data fetching, Jotai shines especially well.
- No mandatory Provider (from certain versions onward).
Disadvantages
Section titled “Disadvantages”- Lower adoption than Zustand or Redux: smaller community, fewer resources, fewer documented patterns.
- Can become hard to follow when you have many atoms with dependencies between them. The dependency graph can be difficult to visualize.
- Mental model shift: switching to thinking in atoms instead of stores requires a mental adjustment that isn’t trivial for everyone.
When to Use It?
Section titled “When to Use It?”When you have very granular state and want precise re-renders. It’s especially interesting in applications with lots of UI interactivity where re-render performance matters, or if you use Suspense heavily for data fetching. It’s also a compelling option if you’re coming from Vue and the reactive model feels natural to you.
Recoil: Facebook’s Experiment.
Section titled “Recoil: Facebook’s Experiment.”What Is It?
Section titled “What Is It?”Recoil is Facebook/Meta’s take on atomic state in React. It shares its philosophy with Jotai (in fact, Jotai was inspired by Recoil), but it comes directly from the house that built React, which in theory sounds promising.
Philosophy
Section titled “Philosophy”Just like Jotai, the model is atomic: state atoms that components consume, and selectors that derive state from those atoms. The main difference from Jotai lies in the implementation and the API, with Recoil being somewhat more verbose.
Advantages
Section titled “Advantages”- Powerful atomic model with
atomandselector. - Well integrated with Suspense and React’s concurrent model.
- Backed by Meta.
Disadvantages
Section titled “Disadvantages”- Uncertain project status: and we have to be honest here. Recoil has been in a questionable maintenance state for a while. It doesn’t receive frequent updates, its core team within Meta appears to have reduced focus on it, and the community has started migrating toward Jotai as a more active alternative with the same philosophy.
- Requires a Provider.
- More verbose API than Jotai.
When to Use It?
Section titled “When to Use It?”Honestly, if you’re evaluating between Recoil and Jotai for a new project, I’d go with Jotai. Same philosophy, cleaner API, active maintenance, and a growing community. Recoil might make sense if you already have a project using it and don’t want to migrate, but for new projects, there are better alternatives.
Head-to-Head Comparison.
Section titled “Head-to-Head Comparison.”| Redux + RTK | Zustand | Context API | Jotai | Recoil | |
|---|---|---|---|---|---|
| Philosophy | One store, strict flow | Multiple small stores | Data distribution | Independent atoms | Atoms + selectors |
| Boilerplate | High | Very low | Medium | Very low | Medium |
| Learning curve | High | Low | Very low | Low-Medium | Medium |
| Scalability | Excellent | Good | Limited | Good | Good |
| Performance | Very good (selectors) | Excellent | Limited | Excellent | Very good |
| DevTools | Exceptional | Good | None | Limited | Limited |
| Async/effects | Very powerful (Saga/Thunk) | Basic | Manual | Basic | Basic |
| Bundle size | Medium | Very small | Native | Very small | Small |
| Community | Huge | Large and growing | N/A | Medium and active | Shrinking |
What About TanStack Query?
Section titled “What About TanStack Query?”TanStack Query (formerly React Query) deserves a special mention, because even though it’s not a global state management library in the traditional sense, you need to know about it.
TanStack Query solves a very specific problem: server state. Meaning, the data that comes from an API. It manages caching, synchronization, refetching, loading and error states, pagination, mutations… in a very elegant way with very little code.
The question I get asked a lot is: does TanStack Query replace Redux? The answer is: it depends on why you’re using Redux. If you’re using Redux mainly to store your API responses and then display them in components, then yes, TanStack Query can replace a large chunk of that usage. If you’re using Redux to manage complex UI state, business flows, feature-specific local state… then they’re complementary, not substitutes.
In many modern projects, the combination of TanStack Query for server state and Zustand for UI state is a very clean and efficient architecture.
Conclusion: Which One Do I Pick?
Section titled “Conclusion: Which One Do I Pick?”There’s no universal answer, but there are reasonable recommendations:
- Small app, prototype, MVP: start with Context API or go straight to Zustand if you anticipate some complexity. Don’t waste time setting up Redux.
- Medium app with a small-to-medium team: Zustand is your best friend. Fast, clean, powerful, and low friction.
- Large app, large team, complex async logic: Redux + RTK + Redux Saga. The investment in setup and learning pays off many times over in maintainability and scalability.
- Very granular state, lots of UI interactivity: consider Jotai, especially if you use or plan to use Suspense extensively.
- Server data: TanStack Query, regardless of whatever you use for UI state.
The day-to-day reality in real projects is that you often combine several of these solutions. There’s nothing wrong with using TanStack Query for requests, Zustand for global UI state, and Context API for the visual theme. What matters is that each tool is solving the problem it was designed for.
The biggest mistake I see repeated constantly is choosing technology based on what looks good on a CV or what appears most in job listings, rather than what the project actually needs. Redux shows up in a lot of job postings because there are a lot of legacy projects using it, not because it’s always the best option.
Choose with criteria, know your tools well, and whatever option you go with, keep it organized. A bad architecture with any library is always worse than a good architecture with any other.