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.
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> </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.
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
Top comments (0)