When building a ReactJS application, managing state efficiently becomes crucial as the app scales. React’s built-in state management is great for small apps, but for larger or more complex applications, an external state management library often becomes necessary.
Zustand is one such lightweight, fast, and minimalistic state management library that can help you manage global states in your React application without adding much complexity.
In this blog, we'll learn how to use Zustand in a simple Todo List App built using Vite.
Here is the working of project:
What is Zustand?
Zustand is a small, fast state management library for React. It provides a simpler API compared to other state management libraries like Redux, making it more user-friendly for small to mid-sized applications.
Why Zustand?
- Simplicity: Zustand provides a simple and minimal API to work with state.
- Performance: Zustand only triggers re-renders in components that use the specific state that has changed.
- No Boilerplate: Unlike Redux, Zustand doesn’t require reducers, actions, or middleware to manage the state.
Getting Started with Zustand and Vite
Step 1: Create a New Project with Vite
First, let’s set up a React project using Vite, which is a fast and modern build tool.
# Create a new Vite project
npm create vite@latest todo-app-zustand --template react
Then follow below steps in terminal:
Then follow below commands :
# Move into the project directory
cd todo-app-zustand
# Install dependencies
npm install
Vite has now created a boilerplate React app. You can run the app using:
npm run dev
Open http://localhost:5173
in your browser to see your new Vite app running.
Step 2: Install Zustand
Now, let's install Zustand to manage the state of our Todo list app.
npm install zustand
Step 3: Set Up Zustand for State Management
Create a new folder called store
in your src
directory and add a file todoStore.js
inside it. This file will hold our Zustand store.
// src/store/todoStore.js
import { create } from 'zustand';
const useTodoStore = create((set) => ({
todos: [],
// Add a new todo
addTodo: (todo) =>
set((state) => ({
todos: [...state.todos, { id: Date.now(), text: todo, completed: false }],
})),
// Remove a todo by ID
removeTodo: (id) =>
set((state) => ({
todos: state.todos.filter((todo) => todo.id !== id),
})),
// Toggle a todo's completion status
toggleTodo: (id) =>
set((state) => ({
todos: state.todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
),
})),
}));
export default useTodoStore;
-
addTodo
: Adds a new todo to the list. -
removeTodo
: Removes a todo by its unique id. -
toggleTodo
: Toggles the completed status of a todo.
Step 4: Create the Todo List Component
Now, we will create a TodoList
component that interacts with Zustand's state.
// src/components/TodoList.jsx
import React, { useState } from 'react';
import useTodoStore from '../store/todoStore';
const TodoList = () => {
const { todos, addTodo, removeTodo, toggleTodo } = useTodoStore();
const [newTodo, setNewTodo] = useState('');
const handleAddTodo = () => {
if (newTodo.trim()) {
addTodo(newTodo);
setNewTodo(''); // Clear the input after adding
}
};
return (
<div>
<h1>Todo List</h1>
<input
type="text"
value={newTodo}
onChange={(e) => setNewTodo(e.target.value)}
placeholder="Add a new todo"
/>
<button onClick={handleAddTodo}>Add</button>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<span
style={{
textDecoration: todo.completed ? 'line-through' : 'none',
cursor: 'pointer',
}}
onClick={() => toggleTodo(todo.id)}
>
{todo.text}
</span>
<button onClick={() => removeTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
};
export default TodoList;
Here, we are using the useTodoStore
hook to:
- Fetch the list of todos.
- Add new todos.
- Toggle the completion status of a todo.
- Delete a todo
Step 5: Add TodoList Component to App
Now, we need to add our TodoList
component to the main App.jsx
file.
// src/App.jsx
import React from 'react';
import TodoList from './components/TodoList';
function App() {
return (
<div className="App">
<TodoList />
</div>
);
}
export default App;
Step 6: Styling (Optional)
You can optionally style your app using your preferred CSS framework, or even install and use Tailwind CSS
or Bootstrap
.
For simplicity, let's add some basic styles directly in index.css
.
/* src/index.css */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f4f4f4;
}
h1 {
text-align: center;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: flex;
justify-content: space-between;
background: #fff;
margin: 10px 0;
padding: 10px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
button {
background: #ff4757;
border: none;
color: white;
padding: 5px 10px;
cursor: pointer;
}
input {
margin-right: 10px;
padding: 5px;
width: 300px;
}
Step 7: Run Your App
Run the app using:
npm run dev
You should now see a functional Todo list where you can:
- Add new todos.
- Mark todos as completed or uncompleted by clicking on them.
- Delete todos.
Conclusion:
In this tutorial, we built a simple Todo List app using React and Zustand for state management.
- Zustand’s simplicity and performance make it a great choice for managing state in small to medium-sized applications.
- It requires far less boilerplate compared to other state management solutions like Redux.
- By using Zustand, you can focus on building your application logic without worrying about managing unnecessary complexity.
That's all for this blog! Stay tuned for more updates and keep building amazing apps! 💻✨
Happy coding! 😊