Get started with Zustand
Published: 2023-02-25 19:18:07

Hello Developers

Today we are going to see how to use Zustand state manager with react.

## Prerequisites
You should have some knowledge of ReactJS 

## Introduction
React is a great tool to create frontend apps. There are lots of tools available to manage state like Jotai, Redux, Recoil etc. There is one tool I like much is Zustand. It require minimum setup to get started. It follow very simple approach and today we are going through this.

## Setup New Project
I am using PNPM & VITE to create and setup new project. You can use npm.
`pnpm create vite@latest` 

Above command ask you to choose framework. Choose React and JavaScript in next step. Now we need to add zustand and other dependencies to our React app.

```
pnpm add zustand uuid react-icons
pnpm add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
```

This will add Zustand to your project and install all dependencies.

Our file structure will be like this.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vg5ebgwl1uce18kk79jd.png)

Very first, we will update the App.jsx file with following code.

```
import TodoForm from "./components/TodoForm";
import TodoList from "./components/TodoList";

function App() {
  return (
    <div className="App">
      <div className="flex">
        <div className="w-1/2">
          <TodoForm />
        </div>
        <div className="w-1/2">
          <TodoList />
        </div>
      </div>
    </div>
  );
}

export default App;
```

Now next part is to create store for our react app. Create new file in new "/store/todoStore.js" and put following code in file.

```
import { create } from "zustand";
import { v4 as uuidv4 } from "uuid";
const todoStore =(set, get) => ({
  todos: [],
  addTodo: (title) => {
    const newTodo = {
      title,
      id: uuidv4(),
      markDone: false,
    };
    set((state) => ({
      todos: [...state.todos, newTodo],
    }));
  },
  markTodoDone: (id, checked) => {
    let newTodos;
    if (checked === true) {
      newTodos = get().todos.map((todo) => {
        return todo.id === id ? { ...todo, markDone: true } : {...todo};
      });
    } else {
      newTodos = get().todos.map((todo) => {
        return todo.id === id ? { ...todo, markDone: false } : {...todo};
      });
    }

    set((state) => ({
      todos: newTodos,
    }));
  },
  removeTodo: (id) => {
    const newTodos = get().todos.filter((todo) => todo.id !== id);
    set(state => ({
      todos: newTodos
    }))
  },
});
const useTodoStore = create(todoStore);
export default useTodoStore;
```

So we have created our store, now we use this store to manage our todos.

**/components/TodoForm.jsx**
```
import React from "react";
import { useState } from "react";
import useTodoStore from "../store/todoStore";
const TodoForm = () => {
  const [title, setTitle] = useState("");
  const addTodo = useTodoStore((state) => state.addTodo);
  const handleAddTodo = () => {
    addTodo(title);
    setTitle("");
  };
  return (
    <div>
      <h1>Todo Form</h1>
      <table className="border-2 w-full">
        <tbody>
          <tr>
            <td>
              <label htmlFor="todo">Todo</label>
            </td>
            <td>
              <input
                placeholder="Todo Text"
                type="text"
                className="border-red-500 border-2"
                name="todo"
                id="todo"
                onChange={(e) => setTitle(e.target.value)}
              />
            </td>
          </tr>
          <tr>
            <td>&nbsp;</td>
            <td>
              <button
                type="button"
                onClick={handleAddTodo}
                className="btn btn-primary"
              >
                Add Todo
              </button>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  );
};

export default TodoForm;

```

**/components/TodoList.jsx**
```
import React from "react";
import {BsTrash} from "react-icons/bs";
import useTodoStore from "../store/todoStore";
const TodoList = () => {
  const todos = useTodoStore((state) => state.todos);
  const markTodoDone = useTodoStore(state => state.markTodoDone);
  const removeTodo = useTodoStore(state => state.removeTodo);
  return (
    <div className="px-3">
      <h1>Todos</h1>
      {todos?.map((todo) => (
        <div className="flex justify-start items-center" key={todo.id}>
          <div className="w-auto">
            <input type="checkbox" name="markDone" onClick={(e) => markTodoDone(todo.id, e.target.checked)} id="" />
          </div>
          <div className="px-3"><BsTrash title="Remove Todo" className="cursor-pointer" onClick={() => removeTodo(todo.id)}/></div>
          <div className={`px-1 w-full ${todo.markDone === true ? 'line-through text-red-700' : ''}`}>{todo.title}</div>
          
        </div>
      ))}
    </div>
  );
};

export default TodoList;
```

**/index.css**
```
@tailwind base;
@tailwind components;
@tailwind utilities;

.btn {
  @apply border-blue-500 bg-blue-800 text-white px-4 py-1 rounded-md;
}

input[type="text"]{
  @apply w-full px-4 py-1 rounded-md;
}
table {
  @apply border-2 border-red-300 shadow-lg w-full;
}
table td{
  @apply px-3 py-2; 
}

table tr:nth-child(even){
  @apply bg-gray-200;
}


table tr:nth-child(odd){
  @apply bg-white;
}
```

**/tailwindcss.config.cjs**
```
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

```
Now you can run the project. You will see same screen if you have followed it here.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c774zvcjj1zbtigsby0s.png)

You can check the code on this link with using of persist middle-ware.

> https://bitbucket.org/deepaksinghkushwah/dev-to-projects/src/main/react-zustand-example/

Happy Coding