Skip to content

Zustand for State Management

Zustand

Intro

State management has always been a challenge for developers working in React. Maybe this is due, in part, to the fact that React is a “library”, not a “framework”. Over the years, we had a lot of great solutions like Redux, Flux, XState, …etc and each new one is better than the previous one! Today, we will learn a brand new state management library not just for React, but it can be used with any other framework.

What is Zustand

Zustand is a small, fast, and scalable bearbones state-management solution using simplified flux principles. It has a comfy API based on hooks, and isn't rigid or opinionated.

Learn Zustand under 30 seconds

First, create the store file, for example: useStore.js:

import create from ‘zustand’;

const useStore = create(() => ({
  name: 'Mark',
}));

Then, import that hook wherever you want.

This is how you get the state:

useStore(state => state.name)

And this is how you set it

useStore.setState({name: ‘John’})

Here is a live example, run npm run dev:

Congratulations, you have the basics! 🎉

Ready to go deeper?

Add actions in the store

The previous example is oversimplified but we can use more advanced examples with actions instead of setting the state directly.

So, let’s create a new store for a counter:

import create from ‘zustand’;

const useStore = create(set => {
	count: 0,
  increment: () => set(state => ({count: state.count + 1})),
  decrement: () => set(state => ({count: state.count + 1})),
})

As you see, we pass the set prop in the function inside create, and we can use it to set the state internally. Also, we can pass the state prop in the set function to access the current state in the store.

Here is a live example, run npm run dev:

Use get() in actions

But what if we need to access one of the current states inside a specific action without using set? Well, there is the get function, and its job is to just get a current state value.

const useStore = create((set, get) => ({
  sound: "grunt",
  action: () => {
    const sound = get().sound
    // ...
  }
})

Async actions

You can use asynchronous actions because Zustand deals with actions as normal functions, so you can easily use an async function like this:

const useStore = create(set => ({
  posts: {},
  getPosts: async () => {
    const response = await fetch('https://jsonplaceholder.typicode.com/posts')
    set({ posts: await response.json() })
  }
}))

Use Zustand with vanilla javascript

Zustand can work outside of React with any JavaScript framework, or just with vanilla JavaScript, without any framework, by using 'zustand/vanilla':

import create from 'zustand/vanilla'

const store = create(() => ({ ... }))

You can then access the store content in other files like this:

const { getState, setState, subscribe, destroy } = store

Why Use Zustand Over Redux or React Context

  • Easy to use
  • Very small library
  • Can be used with other frameworks or vanilla javascript
  • Has better performance since it will inform components transiently (it doesn't force React to re-render the component because the state has changed)
  • Allows developers to avoid over-engineering, especially in big projects