Using Zustand in React applications

Olena Drugalya - May 16 '22 - - Dev Community

In this post we are going to look closely to one of the state management libraries - Zustand.
This is a good alternative to Redux for development of React applications if you find Redux too complicated or too heavy for your current project.

What is Zustand?

Zustand (a german word that means 'state' in English) - a state-management library. In official documentation they call it "a small, fast and scalable bearbones state-management solution".
It helps to solve such problems as "zombie child" problem, React concurrency and context loss between mixed renderers.
If you want to read about those issues more detailed, here are the links:

How to use Zustand?

Below you will find the step-by step guide about how to use Zustand in your React project.
Before you follow the steps, make sure that you can created a react project either with CRA or Vite and it is up and running.

Step 1 - Import

This library can be imported to your project very easy with npm or yarn:

npm install zustand
Enter fullscreen mode Exit fullscreen mode
yard add zustand
Enter fullscreen mode Exit fullscreen mode

Step 2 - Create Store

Zustand gives us possibility to use the state in any component in our application. In order to do that, we need to create a store for the state.
We will be using a simple To-Do app as an example here.
In the project files we create a folder which we call 'store' and in this folder we create a file with the name 'useToDoStore.ts'.
Remember, that Zustand store is a hook so it has to be named with 'use' at the beginning (rule of custom hooks)

Inside 'useToDoStore.ts' file we create first an interface for our to-do task:

interface ToDo {
  id: string;
  title: string;
}
Enter fullscreen mode Exit fullscreen mode

After that we create an interface for our ToDoStore, which will include an array of ToDos and methods to create, update and delete ToDos:

interface ToDoStore {
  toDos: Todo[];
  createToDo: (title: string) => void;
  updateToDo: (id: string, title: string) => void;
  deleteToDo: (id: string) => void;
}
Enter fullscreen mode Exit fullscreen mode

Now we can continue and create actually a store. To do this, we need to import a specific method create from the Zustand library and than use this method to create a store:

import create from "zustand";

export const useToDoStore = create<ToDoStore>((set, get) => ({
  todos: [], // our array of todos is empty but
             // it could be predefined as well
  createToDo: (title) => {},
  updateToDo: (id, title) => {},
  deleteToDo: (id) => {},
}));
Enter fullscreen mode Exit fullscreen mode

Method create give us access to 2 important functions:

  1. set() - this function update the current state
  2. get() - this function gives access to the current state to outside Those functions work the same way as setters and getters in the class. We will use them when defining our store functions for ToDos.

Step 3 - Create Functions

Here we will use set() and get() functions from create to define what our store functions will do.

Let's start from the function which creates todos:

  createToDo: (title) => {
  const { todos } = get(); // first we get all todos
    const newTodo = {
      id: generateId(),// helper function to create ID
      title,
    };
    set({
      todos: [...todos, newTodo]
    });
  },
}
Enter fullscreen mode Exit fullscreen mode

Than we create a function which updates todos:

 updateToDo: (id: string, title: string) => {
    const { todos } = get();
    set({
      todos: todos.map(todo =>({
        ...todo,
        title: todo.id === id? title : todo.id
      }))
    })
  }

Enter fullscreen mode Exit fullscreen mode

And the function which deletes todo:

deleteToDo: (id: string) => {
    const { todos } = get();
    set({
      todos: todos.filter(todo => todo.id !== id)
    })
  },

Enter fullscreen mode Exit fullscreen mode

Congratulations, we have a store now :) Lets use it!

Step 4 - Use Store

To use a store, go to the file with a component (for example ToDoList.tsx), import the ToDoStore and destructure the state and/or necessary methods from the hook. You can use all methods or just specific method in any component:

 const [todos, createToDo, updateToDo, deleteToDo] = useToDoStore((state) => [
    state.todos,
    state.createToDo,
    state.updateToDo,
    state.deleteToDo,
  ]);

Enter fullscreen mode Exit fullscreen mode

Now your state can be used in the file of specific component where you need it to be used. Use the hook anywhere without any providers.

Conclusion

  • this library is small and easy to use
  • renders components only on change
  • no context providers needed
  • can be used without React

If you want to learn more about Zustand and what is proposes, visit the official page at https://github.com/pmndrs/zustand

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .