Building a Todo App with React Context

Photo by Kyle Glenn on Unsplash

Building a Todo App with React Context

For reference, my GitHub repository is also available,

Extra: Tailwind CSS style, Vite Tool for reduced loading time.

GitHub Link: https://github.com/prasadpatil1123/react/tree/main/todocontextLocal10

Introduction

In the world of web development, Todo applications serve as the "Hello World" for learning a new framework or library. In this tutorial, we'll explore how to build a Todo app using React and manage the state globally using React Context.

Setting Up the Project

Let's start by setting up a new React project. If you haven't already, you can create a new project using Create React App:

npx create-react-app react-context-todo
cd react-context-todo

Now, let's implement the Todo functionality step by step.

Creating the Todo Context

In React, context provides a way to pass data through the component tree without having to pass props down manually at every level. In our case, we want to manage the state of our Todo items globally.

Create a new file TodoContext.js:

// TodoContext.js
import React, { createContext, useContext } from 'react';

export const TodoContext = createContext({
  todos: [],
  addTodo: () => {},
  updateTodo: () => {},
  deleteTodo: () => {},
  toggleComplete: () => {},
});

export const useTodo = () => {
  return useContext(TodoContext);
};

In this file, we define a TodoContext using createContext and a custom hook useTodo to consume the context.

Implementing TodoProvider

Now, let's create a component that will act as our context provider. Create a file TodoProvider.js:

// TodoProvider.js
import React, { useState, useEffect } from 'react';
import { TodoContext } from './TodoContext';

const TodoProvider = ({ children }) => {
  const [todos, setTodos] = useState([]);

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

  const updateTodo = (id, todo) => {
    setTodos((prev) => prev.map((prevTodo) => (prevTodo.id === todo.id ? todo : prevTodo)));
  };

  const deleteTodo = (id) => {
    setTodos((prev) => prev.filter((todo) => todo.id !== id));
  };

  const toggleComplete = (id) => {
    setTodos((prev) =>
      prev.map((prevTodo) =>
        prevTodo.id === id ? { ...prevTodo, completed: !prevTodo.completed } : prevTodo
      )
    );
  };

  useEffect(() => {
    const savedTodos = JSON.parse(localStorage.getItem('todos'));
    if (savedTodos && savedTodos.length > 0) {
      setTodos(savedTodos);
    }
  }, []);

  useEffect(() => {
    localStorage.setItem('todos', JSON.stringify(todos));
  }, [todos]);

  return <TodoContext.Provider value={{ todos, addTodo, updateTodo, deleteTodo, toggleComplete }}>{children}</TodoContext.Provider>;
};

export default TodoProvider;

This component provides the TodoContext values and manages the state of our Todo items.

Building the Todo App

Now, let's create the main component that will use our Todo context. Modify the App.js file:

// App.js
import React from 'react';
import './App.css';
import TodoProvider from './TodoProvider';
import { TodoForm, TodoItem } from './components';

function App() {
  return (
    <TodoProvider>
      <div className='bg-[#172842] min-h-screen py-8'>
        <div className='w-full max-w-2xl mx-auto shadow-md rounded-lg px-4 py-3 text-white'>
          <h1 className='text-2xl font-bold text-center mb-8 mt-2'>Manage your Todos</h1>
          <div className='mb-4'>
            <TodoForm />
          </div>
          <div className='flex flex-col gap-y-3'>
            <TodoItem />
          </div>
        </div>
      </div>
    </TodoProvider>
  );
}

export default App;

Here, we wrap our app with the TodoProvider to provide the Todo context to all components.

Creating TodoForm and TodoItem

Now, let's create the TodoForm and TodoItem components as described in the previous code snippets.

Your project structure should look like this:

src
|-- components
|   |-- TodoForm.js
|   |-- TodoItem.js
|-- contexts
|   |-- TodoContext.js
|-- TodoProvider.js
|-- App.js

Conclusion

Congratulations! You've successfully built a Todo app using React and managed the state globally using React Context. This is just a starting point, and you can enhance the app by adding more features like filtering, sorting, or even integrating with a backend for persistent storage.

Feel free to explore further and customize the app based on your preferences. Happy coding!