DEV Community

Cover image for Reactjs Todo List App (Using Vite & Zustand)
Jagroop Singh
Jagroop Singh

Posted on

Reactjs Todo List App (Using Vite & Zustand)

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:

Screen of Adding Todo List

Screen to Delete Todo's (if completed)

Marking completed for Completed todo

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
Enter fullscreen mode Exit fullscreen mode

Then follow below steps in terminal:

selecting reactjs

choosing javascript

Then follow below commands :

# Move into the project directory
cd todo-app-zustand

# Install dependencies
npm install
Enter fullscreen mode Exit fullscreen mode

Vite has now created a boilerplate React app. You can run the app using:

npm run dev

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;

Enter fullscreen mode Exit fullscreen mode
  • 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;

Enter fullscreen mode Exit fullscreen mode

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;

Enter fullscreen mode Exit fullscreen mode

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;
}

Enter fullscreen mode Exit fullscreen mode

Step 7: Run Your App
Run the app using:

npm run dev
Enter fullscreen mode Exit fullscreen mode

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! 😊

Top comments (10)

Collapse
 
sherif_san profile image
Sherif sani

Thanks for sharing πŸ™β˜ΊοΈ

Collapse
 
jagroop2001 profile image
Jagroop Singh • Edited

Thanks @sherif_san πŸ™

Collapse
 
john12 profile image
john • Edited

@jagroop2001 ,Great tutorial! The step-by-step guide was very clear and helped me understand how to integrate Zustand into my React app. Thanks for sharing!

Collapse
 
jagroop2001 profile image
Jagroop Singh

Thanks @john12

Collapse
 
works profile image
Web

@jagroop2001 , Great tutorial. I came into this while searching for learning zustand. This is really beneficial.

Collapse
 
jagroop2001 profile image
Jagroop Singh

Thanks @works πŸ™

Collapse
 
elielson77 profile image
Elielson Melo

Very nice post!

Collapse
 
jagroop2001 profile image
Jagroop Singh

Thanks @elielson77 πŸ™

Collapse
 
tomasdevs profile image
Tomas Stveracek

Great article! Zustand seems really simple and fast for small apps like this todo list. How long did it take you to learn and use it in this project?

Collapse
 
jagroop2001 profile image
Jagroop Singh

@tomasdevs , I worked with Zustand before, though I didn't initially realize it because I learned it while understanding a project at my office. From project ideation to final revisions, it typically takes me around 2 hours approximately.