Skip to content

atharv-hacking/Todo-List-Web

Repository files navigation

✅ React Todo App using Context API

A fully functional Todo List application built using React, Context API, and Tailwind CSS. The app supports adding, editing, completing, and deleting todos, with persistent storage using localStorage.


📦 Features

  • Add new todos
  • Edit existing todos
  • Mark todos as completed/uncompleted
  • Delete todos
  • Auto-save todos to localStorage
  • Fully styled with Tailwind CSS
  • Global state management using Context API

🛠️ Tech Stack

  • ⚛️ React (Hooks, Functional Components)
  • 🎯 Context API for state management
  • 💾 LocalStorage for data persistence
  • 🎨 Tailwind CSS for styling
  • 🔀 JavaScript (ES6+)

📂 Folder Structure

src/
│
├── components/
│   ├── TodoForm.jsx      // Input field + Add button
│   └── TodoItem.jsx      // Each todo item with edit, delete, complete
│
├── contexts/
│   └── TodoContext.js    // React Context logic for global state
│
├── App.jsx               // Main app with all logic and provider
└── index.css / main.jsx  // Tailwind CSS & entry point
int
try point

🔄 How It Works

1. Context Setup

We use createContext() to create TodoContext:

export const TodoContext = createContext(defaultValue)

Then we wrap the app with the provider in App.jsx:

TodoProvider value={{todos, addTodo, updateTodo, deleteTodo, toggleComplete}}>gt;

All components now have access to these via a custom hook:

export const useTodo = () =>gt; useContext(TodoContext);

2. State & Logic in in App.jsx

We keep the main todo list in state:

const [todos, setTodos] = useState([]);

✅ Add Todo

setTodos(prev =>gt; [{ id: Date.now(), ...todo }, ...prev]);

✏️ Update Todo

setTodos(prev =>gt; prev.map(t =>gt; t.id === id ? updatedTodo : t));

❌ Delete Todo

setTodos(prev =>gt; prev.filter(t =>gt; t.id !== id));

✅ Toggle Completion

setTodos(prev =>gt; prev.map(t =>gt; t.id === id ? { ...t, completed: !t.completed } : t));

3. LocalStorage Integration

To persist todos across reloads:

✅ Load on mount:

useEffect(() =>gt; {
   const todos = JSON.parse(localStorage.getItem("todos"));
   if (todos?.length) setTodos(todos);

}, []);

💾 Save on change:

useEffect(() =>gt; {
   localStorage.setItem("todos", JSON.stringify(todos));

}, [todos]);

4. TodoForm Component

  • Uses useState to manage input text
  • Calls addTodo() from context on submit
  • Clears input after adding
addTodo({ todo, completed: false });

5. TodoItem Component

Each todo can be:

  • Toggled (via checkbox)
  • Edited (via input + save button)
  • Deleted (via ❌ button)

The component uses:

updateTodo(todo.id, { ...todo, todo: todoMsg });

toggleComplete(todo.id);

deleteTodo(todo.id);

It manages local state for editing via:

const [isTodoEditable, setIsTodoEditable] = useState(false);

💡 Code Highlights

  • Date.now() used for unique IDs.
  • Spread operator ({ ...todo, todo: updatedMessage }) ensures immutability.
  • Controlled inputs maintain form data in state.
  • Tailwind CSS provides fast styling without writing custom CSS.

🚀 How to Run Locally

git clone repo-url>gt;

cd project-directory>gt;
npm install
npm run devev

Open http://localhost:5173 in your browser.


🧠 Key Learnings

  • Using Context API for clean state management across components
  • Avoiding prop drilling with useContext()
  • Leveraging custom hooks for cleaner access
  • Persisting state with localStorage
  • Practicing React patterns with functional components & hooksooks

📌 Improvements You Can Try

  • Add filters (All, Active, Completed)
  • Use uuid instead of Date.now() for better ID generation
  • Add animations with Framer Motion
  • Add authentication and save todos per user using Firebase or Supabase