Using Zustand in React applications
Published: 2022-05-16 12:52:51

In this post we are going to look closely to one of the state management libraries - **Zustand**. 
This is a good alternative to [Redux](https://redux.js.org/) 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](https://react-redux.js.org/api/hooks#stale-props-and-zombie-children), React concurrency and context loss between mixed renderers. 
If you want to read about those issues more detailed, here are the links: 
- React concurency - https://github.com/bvaughn/rfcs/blob/useMutableSource/text/0000-use-mutable-source.md. 
- context loss - https://github.com/facebook/react/issues/13332
AND the most beauty of it is that the store it provides is a **hook** and you can put objects or functions in it. How awesome is that!

## 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
```
````
yard add zustand
```
## 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](https://reactjs.org/docs/hooks-custom.html))

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

```react
interface ToDo {
  id: string;
  title: string;
}
```
After that we create an interface for our ToDoStore, which will include an array of ToDos and methods to create, update and delete ToDos:

```react
interface ToDoStore {
  toDos: Todo[];
  createToDo: (title: string) => void;
  updateToDo: (id: string, title: string) => void;
  deleteToDo: (id: string) => void;
}
```
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:

```react
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) => {},
}));
```
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:

```react
  createToDo: (title) => {
  const { todos } = get(); // first we get all todos
    const newTodo = {
      id: generateId(),// helper function to create ID
      title,
    };
    set({
      todos: [...todos, newTodo]
    });
  },
}
```
Than we create a function which updates todos:

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

```
And the function which deletes todo:

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

```
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:

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

```
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