There are many state management libraries for React. The most popular is Redux, with over 4 million downloads per week. Redux dominates the competition. However, many other state management libraries have emerged in recent years. Some of these libraries follow the flux pattern defined by Facebook, and others have an atomic model popularized by Recoil (also developed by Facebook).

Redux domination is apparent - Source

Why do we need state management?

React applications are built using separate components. One good practice is to create many small components to make them reusable and easier to maintain. As the project grows, the number of components increases, and sharing data across the code becomes tedious.

Updating one piece of information in an application can require the update of several components. For example, that's the case when someone adds an item to a shopping list or when a user logs in.

Adding one item to the shopping cart updates many components

That's where state management libraries come in handy. They offer a way to store data that will be shared across the application. It becomes possible, for example, to access user information on every component of the application, which is quite helpful in personalizing the UI or authenticating API calls.

In the Zalando example, adding one item to the shopping list adds a badge on the icon and opens the shopping list. Those components are separated, and using a state management library is critical to avoid components with dozens of props.

This is not something you want to see! 

Enter Zustand

Out of all the existing libraries, one stood out for me. It's called Zustand, meaning "state" in German. It is self-described as a small, fast and scalable state management. The solution is attractive since it's speedy to implement and requires little boilerplate. I often say that "the less code, the better", having a state management library that follows this principle is excellent. Less code means more straightforward code to maintain, which is critical in web agencies where time is limited.

Besides its simplicity, Zustand has built-in middleware that enhances the basic state. I didn't use all of them, but two are interesting:

  • persist: save the data to the local storage (or another browser storage if desired) and sync the data when the application load. This is handy to store user settings, for example.
  • devtools: sometimes, working with a state is hard since we don't know what is stored. Instead of spamming console.log throughout the application, Zustand supports the Redux dev tools. Adding this middleware to any store allows developers to see the store's contents from within the Redux browser extension.

How to Use Zustand

Enough presentation. Let's see how to use Zustand. To showcase the library, I created a project that can be found on Github. It's a simple React application in JavaScript that has two stores:

  • configStore: saves (and persists on the local storage) user settings. A user can enable the dark team with the press of a button. Since the store persists, the theme is saved locally. This means that settings are retrieved from the local storage on app load.
  • todoStore: stores a list of todo a user might have. Dummy data is loaded and saved at the app start. It's then possible for a user to mark as complete, remove and add todos.

The first step once you have installed Zustand is to create a store. For that, create a file and create an object. The following screenshot shows how easy it is to make the configStore with the persist middleware.

What if you want to have a more complex store? For example, when completing a todo, you have to change the appropriate item on the list. It's easy to write JavaScript in setters. The following screenshot shows how the todoStore is created. It uses the devtools middleware.

As you can see, creating stores is easy. You create the properties you want and some methods to mutate them. Now that the store is created you have to use its data. Getting the data from the store can be done from any component with ease.

And that's it! You now have components that will automatically re-render on change. Writing less than 50 lines was enough to have a global state which is pretty impressive if you ask me!

Here is the final demo where everything is working!

Avoid object deconstruction

When using multiple properties of a store, it can be tempting to deconstruct the object instead of writing one line for every prop you want. This is considered a bad practice and can cause performance issues. Re-render will occur when a property changes, the deconstruction of the object will lead to more re-renders, thus reduced performances.

Why Zustand and not Redux or React Context

There are several reasons to choose Zustand over Redux or React Context. The team puts forward the following arguments.

For Redux:

  • Simple and un-opinionated
  • It makes hook the primary means of consuming state
  • Doesn't wrap your app in context providers
  • Can inform components transiently (without causing render)

For React Context:

  • Less boilerplate
  • Renders components only on changes
  • Centralized, action-based state management

Personally, I like the simplicity of Zustand. As said before, less than 50 lines of code are needed to add a state management solution to your application and consume its data. This is the reason why I love using Zustand over Redux or Context.

Atomic State Management

Atomic state management libraries such as Recoil or Jotai have been getting more traction in the past years. They provide a simple way to handle state and can be an excellent replacement for other libraries. I don't have any experience with either of them, so I don't have many insights.

While researching this article, I decided to give Jotai a spin and was quite pleased with its work. As you can see in the following example, using Jotai is like working with the classic useState hook, which is fantastic.

Demonstration on how simple it is to use Jotai - Source

Funnily enough, I discovered that react-spring was responsible for both Zustand and Jotai! This might explain why both names mean state in different languages and why both solutions are elegant and un-opinionated.

Final words

The goal of this article was not to argue which state management library is best. I wanted to share a library that I use and appreciate daily. The speed and ease of use of Zustand made me forget Redux very quickly. We adopted Zustand for about a year at my current job, and we never looked back.

Jotai is also very interesting and approaches the state management question from a different angle. It's an internal state which can be interesting in some cases. The team behind both projects thinks that both libraries have use and lets the users decide which one they prefer. Since none are opinionated, the choice will depend on user preferences.

The whole project is available on GitHub, and you can play with it in a code sandbox if you don't want to clone it.

Feel free to leave a comment to share your experience with state management. If you want to contact me, you can send me an email. I will be very happy to share with you. If you do not want to miss an article, please subscribe to the newsletter. You will only receive emails when I publish a new article.