Lorenz Weiß Hi, I'm Lorenz, a frontend-focused web developer. I'm in love with the internet and its people and interested in everything related to it.

Using Zustand to simplify state management

4 min read 1351

Zustand State Management

To manage state in modern frontend frameworks, Redux has always been king. But now, many new competitors are entering the fray with new ideas, desperate to overthrow Redux with the promise of ease-of-use and simplicity.

I, for one, am excited about the growing number of new ways to manage your state. In this article, I’ll cover probably the simplest and smallest of all: Zustand.

You’ll learn what Zustand is, how it differs from other modern tools like Jotai or Recoil, and when you should use it over Redux.

What is Zustand?

First of all, I’m not claiming that Zustand is currently the best tool to use. As in most cases, the question of which tool is the best cannot really be answered, or at least it must be answered with the dreaded phrase, “It depends.”

Funny Tweet

To get the full picture of Zustand, let’s go over some of the details of the library and how it is positioned in the market and compared to other libraries.

Zustand was created and is maintained by the creators of react-spring, react-three-fiber, and many other awesome tools, Poimandres. At 1.5kB, it’s probably the smallest library of all — you can read through the source code in a matter of minutes.

Getting started with Zustand

Zustand is known for its simplicity. On the (really beautiful) website they created for their package, you can see a very simple example written in just four lines of code that creates a globally available state:

import create from 'zustand'

const useStore = create(set => ({
  bears: 0,
  increasePopulation: () => set(state => ({ bears: state.bears + 1 })),
}))

The main function from the state management library is called create. It accepts a callback function as its first argument, which in turn accepts a set function that should be used when manipulating memory.

The function create then returns another function, which in our case, is called useStore. As you can see from the name of the return value, it returns a hook, so you can insert it anywhere in your React application, like so:

We made a custom demo for .
No really. Click here to check it out.

function BearCounter() {
  const bears = useStore(state => state.bears)
  return <h1>{bears} around here ...</h1>
}

Wherever this hook is injected and the state is used, the component will be re-rendered when the state has changed, making it a fully functional global state with these small lines of code.

You could also extract the action, which changes the state anywhere you want from the same hook like this:

function Controls() {
  const increasePopulation = useStore(state => state.increasePopulation)
  return <button onClick={increasePopulation}>one up</button>
}

But what about performing async actions or fetching something from a server that you save to your store?

const useStore = create(set => ({
  fishies: {},
  fetch: async pond => {
    const response = await fetch(pond)
    set({ fishies: await response.json() })
  }
}))

Well, you can make your mutation function asynchronous and Zustand will set your state when it’s ready. That way you don’t really have to worry about asynchronous functions inside your component anymore.

State management can almost not be simpler, right? But it looks very similar to other modern tools like Jotai or Recoil, you say? It may seem that way, but let’s look at some of the differences between these libraries.

How is Zustand different from Jotai and Recoil?

Interestingly, libraries Jotai and Zustand are from the same creators. But the difference lies in the mental modal and how you would like to structure your application.

Zustand is basically a single store (you could create multiple stores, but they are separated.) Jotai is primitive atoms and composing them. In this sense, it’s the matter of programming mental model.

Jotai can be seen as a replacement for useState+useContext. Instead of creating multiple contexts, atoms share one big context. Zustand is an external store and the hook is to connect the external world to the React world.

The last sentence is, in my opinion, the most important one when it comes to what makes Zustand so different from other state management tools. It was basically built for React, but is not tied to it.

This means it could be a tool to connect the React world with the non-React world. How is this possible? Because the state is not built on top of react’s context API. You probably also noticed that you don’t need to add a root provider somewhere in your application during installation.

What makes Zustand so special?

Here’s what impresses me about Zustand.

  1. You CAN use the Redux devtools. One of the first arguments you get when discussing Redux versus another library is that the Redux development tools are powerful. First of all, I don’t think you should decide a library only by its debug tools, but it is a valid argument. But in Zustand, you could use the debug tool as it would be in Redux store. Isn’t that amazing?
    Redux Debug Tool
  2. Zustand is not only for React. I’ve mentioned it before, but what makes Zustand a great tool is that it’s not tied to the React context, and thus, not even tied to use within a React application or React itself. For example, you can combine the state of different applications no matter what framework they use (I’m looking at you, micro frontends).
  3. It’s 100% un-opinionated. Well, this sounds pretty obvious, but in the world of state management in React, I immediately jumped on the Redux ecosystem bandwagon without even thinking about what benefits it could bring. Zustand is one of the examples (and this is also true for the other libraries like Jotai or Recoil) where simplicity wins over over-engineering.
  4. Zustand offers awesome built-in middleware. Zustand comes with some nice batteries-included middleware like the persist feature, which persists your store in any you want. This is the only thing you need to do to make your state persisted in the sessionStorage of your application:
import create from "zustand"
import { persist } from "zustand/middleware"

export const useStore = create(persist(
  (set, get) => ({
    fishes: 0,
    addAFish: () => set({ fish: get().fish + 1 })
  }),
  {
    name: "food-storage", // unique name
    getStorage: () => sessionStorage, // (optional) by default the 'localStorage' is used
  }
))

Disadvantages of using Zustand

Overall, Zustand is a great library for pragmatic programmers and those who use React, but in combination with another library.

However, Zustand has its pros and cons.

  1. The documentation could be improved. As of the time of writing, the only documentation at the moment is the project’s readme. It’s well written so that you can easily understand the library, but it doesn’t cover 100% of all use cases. For instance, if we look at the persist function, you can see two configuration options in the example, but to see all available options you need to open the code and check the implementation directly. Or, if you are using TypeScript, you might figure it out by the typings.
  2. Store structure is clunky. Creating a store must always be done within the create function, and the edit functions need the set function added to the callback function. This means you must write your state functions within the scope of the callback function or you must pass the set function to it. This can be clunky when writing more complex manipulation functions.

The current state of state management

In my opinion, the days of how we used Redux originally are numbered. Global state management can be quite tricky and, therefore, should be something that is not made artificially complicated.

I’m not saying Redux isn’t useful, but it can cause you to over-engineer your initially simple state, which is why I was so impressed with the idea that Zustand touts simplicity. Now, we have plenty of options to choose from, so Redux may no longer be the default go-to for all of your state management.

But in the end, it can really vary from project to project and to say that there is now this one library that solves all of our problems is not realistic, but at least we are now getting more and more options and it should not be the default option to choose Redux for your state management in all applications.

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Lorenz Weiß Hi, I'm Lorenz, a frontend-focused web developer. I'm in love with the internet and its people and interested in everything related to it.

2 Replies to “Using Zustand to simplify state management”

  1. Look at Hookstate https://hookstate.js.org, you will be very much surprised how simpler it is, more feature rich and incredibly fast, especially for the deep nested state updates, which are the problem for all other state management tools.

Leave a Reply