There's always been a myriad of ways to manage state in React. Redux has always been a popular choice, but with React 16, and recently released libraries, there are now even more options. What are these options, and why would you use any of these over any others?
I've gone through some popular choices for managing state in React, and created very simple todo apps to demonstrate their usage. I've tried to keep things as simple as possible, so that you can directly compare these examples. The source is annotated with comments, so take a look and see what best fits your use case!
React's setState()
State is discussed at the start of many different React tutorials for a reason. It's included as a part of React, and is a core part of the way the framework works.
This is referred to as "local state" in the react docs, "state". Here we will call it "setState()" to differentiate from the other approaches.
setState() is a simple way to manage your application state, and doesn't require any libraries beyond just React.
There are some good reasons to use setState():
Your state is not entirely describable as plain objects (you may store unserializable state in setState(), such as DOM nodes, or objects with circular references)
Your changes are not pure functions, and depend on the "outside world" (like, the browser) to determine how state should change
You don't need a global view of the UI – your state will never be persisted or stored remotely.
✨ Example
There's annotated source available for a comparative example.
Redux
Redux is a popular alternative to using setState() when the above constraints no longer hold true. Redux is a set of tools for writing to and reading from a global state in a functional, consistent way. React redux provides a convenient way of mapping your redux state onto React components.
Async redux
For async and remote state, Redux thunk and Redux saga are popular choices. Redux thunk uses redux middleware to allow actions to be async functions, and redux saga uses a pattern that allows easy handling of async behaviour and side effects.
Redux observables is a way of allowing all the power of observables in your state management, pluggin RxJS into redux through some middleware. rxmarbles provides some great examples to give you and idea of what's possible here.
While Redux thunk and Redux saga make async state management with redux easier, but can become one more thing for developers to learn regarding state management.
⚠️ Redux is the de-facto standard for state management in React, but you might not need Redux (by Dan Abramov, a co-author of redux!). Choosing something more complicated than you need will slow you down and complicate simple state changes. This applies to other items in the list - you might not need anything other than setState().
The questions to ask are explained well in you might not need Redux, but in summary – Redux is good if you need serialisable state with an opinionated way of managing global state, but can be overkill for some use cases.
✨ Example
Apollo link state
Apollo link state is a way to combine your local state management with your remote state management. The approach assumes you are using Apollo, which allows you to use GraphQL over Rest. However, you do not need a GraphQL server in order to use this approach! – apollo-link-http allows you to write everything you need to adopt Apollo client side. This means that it's a viable all-in-one solution for state management (async and remote included), even if you aren't using GraphQL.
The way that local and remote state becomes intermingled is through your queries and mutations. apollo-link-state
gives you access to a special @client
directive that tells Apollo to look for this piece of state in local memory, rather than some remote server.
query GetTodos {
items @client {
id
text
done
}
}
Getting Apollo set up just for state management can be a bit of work, but the payoff is a natural way of querying and mutating state, combining local and remote state management.
For simple use cases, and apps that don't heavily depend on async or remote state, Apollo link state is surely overkill. For more involved use cases, Apollo can help by consolidating state management into one system.
✨ Example
Unstated
React 16 has brought with it a new context API, which is a nice way of sharing information around React's virtual tree. Unstated is a library that makes the most of this – it's a light weight way of managing global state across your application.
It's similar to Redux conceptually, but with less opinions about how you should use it. The state is not sliced up into different sections, and defining "actions" is left to you. The API is very similar to React's setState() in shape.
⚠️ Given this, if you're using Unstated, you should again carefully consider if setState() is sufficient for your use case. From the unstated readme:
The unstated readme gives good guidance about when to use alternatives such as Apollo, libraries, or Backbone models and collections.
From the readme:
Unstated isn't ambitious, use it as you need it, it's nice and small for that reason. Don't think of it as a "Redux killer". Don't go trying to build complex tools on top of it. Don't reinvent the wheel. Just try it out and see how you like it.
If you're looking for a simple, un-opinionated state management system and don't want the overhead of alternatives, it's worth looking at.
✨ Example
Honourable mentions
This is not an exhaustive list! I've included some references to alternatives not mentioned here that I haven't yet been able to create examples for or include here.
Stockroom lets you offload your store management to a web worker! This frees up the main thread from computation, and makes all of your requests to read and modify state async.
Backbone models and collections is a well known alternative, and might be sufficient for your use case.
Alfa is a very small and simple state management option.
MobX is a popular choice (hoping I get a chance to try this and add it to the blog!)
Summary
React doesn't include this type of state management itself, which leads to this rise of alternative state management systems. It can be hard to make this choice, but it's good to be allowed the choice – different problems work better with different solutions, and it's nice that React is flexible enough to work with all of them :)
👋 Hi! I’m Joshua Nelson. I’m a developer who cares about making the web a better, for everyone ✨
Top comments (8)
Great post! That's really a lot of useful information about various ways for managing application state.
I have to disagree here. Redux Saga is not using Observables/Rx approach. The concepts seem similar, but they are in fact quite different:
While observables are active event emitters, a Saga's (or in general Generators) execution is being controlled externally by the saga middleware.
The general concept of Redux Saga is actually communicating sequential processes (CSP).
Using RxJS as side effect middleware in Redux is also possible, though (see Redux Observable).
Nevertheless: Thx for the article! Keep writing! <3
Best,
Jonas
Thanks for your comment! That's a good amount of nuance – better than I have on how redux saga works :) I'll add some more info to the post.
Edit: I now see that I actually meant redux observable, thanks!
Very helpful synopsis; thank you!
I'm curious what you'd think of react-easy-state and react-easy-params.
Also, in application after application, I keep getting screwed up by my tendency to implement everything with classes, especially now that ES6 etc. has a decent syntax for them. But then my objects end up not serializable, so saving stuff to redux or easy-state or anything else ends up with horrible kludges. Also, I've got a lot of complex (read-only) remote data I have to query, so I got excited a couple months ago by Apollo link state, but that totally befuddled me. I'll check out Unstated.
Yep – it can be tricky with Apollo link state. If you're already querying remote state, Apollo has some benefits for the local state too.
What type of use case do you have for serializing whole objects to your state? I wonder if there would be ways of not needing to do that at all.
useState can be adapted to manage the global state too, even when the global state can be changed by external events, even when components are not mounted. I have replaced Redux and Mobx in all my project by this tiny library github.com/avkonst/react-use-state-x. It made source code a lot simpler and cleaner. The library uses only hooks for global state management and I maintain it.
Hey, Joshua. Nice post. Try this github.com/lsm/alfa It's even simpler than Unstate.
Nice! I'll add that to the list of honourable mentions :)
Thanks!