Project Overview
In this final project, you'll build a complete Todo application that combines everything you've learned: components, state, hooks, context, routing, and localStorage persistence.
The app will have full CRUD functionality (Create, Read, Update, Delete), filtering, and data persistence across page reloads.
- Add, edit, and delete todos with a clean UI
- Mark todos as complete/incomplete
- Filter by: All, Active, Completed
- Persist data to localStorage
- Use React Router for navigation
- Use Context API for state management
Notes
- This project brings together all the concepts from the course. Take your time and build each feature incrementally.
Core Components
The app is built from several components: App (main layout and routing), TodoList (displays filtered todos), TodoItem (individual todo with edit/delete), and AddTodo (form to create new todos).
Example
import { useState, useContext } from 'react';
import { TodoContext } from './TodoContext';
function AddTodo() {
const [text, setText] = useState('');
const { addTodo } = useContext(TodoContext);
function handleSubmit(e) {
e.preventDefault();
if (!text.trim()) return;
addTodo(text.trim());
setText('');
}
return (
<form onSubmit={handleSubmit}>
<input
value={text}
onChange={e => setText(e.target.value)}
placeholder="What needs to be done?"
/>
<button type="submit">Add</button>
</form>
);
}
function TodoItem({ todo }) {
const { toggleTodo, deleteTodo } = useContext(TodoContext);
return (
<li className={todo.done ? 'completed' : ''}>
<input
type="checkbox"
checked={todo.done}
onChange={() => toggleTodo(todo.id)}
/>
<span>{todo.text}</span>
<button onClick={() => deleteTodo(todo.id)}>Delete</button>
</li>
);
} Notes
- Start by building the TodoContext with useLocalStorage for persistence. Then build each component one by one, testing as you go.
Todo Context with Persistence
The TodoContext manages all todo state and provides functions to add, toggle, and delete todos. Using the useLocalStorage custom hook from Lesson 13 ensures data persists across page reloads.
Example
import { createContext } from 'react';
export const TodoContext = createContext();
function useLocalStorage(key, initial) {
const [value, setValue] = useState(() => {
const saved = localStorage.getItem(key);
return saved ? JSON.parse(saved) : initial;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
export function TodoProvider({ children }) {
const [todos, setTodos] = useLocalStorage('todos', []);
const addTodo = (text) => {
setTodos([...todos, {
id: crypto.randomUUID(),
text,
done: false
}]);
};
const toggleTodo = (id) => {
setTodos(todos.map(t =>
t.id === id ? { ...t, done: !t.done } : t
));
};
const deleteTodo = (id) => {
setTodos(todos.filter(t => t.id !== id));
};
return (
<TodoContext.Provider value={{ todos, addTodo, toggleTodo, deleteTodo }}>
{children}
</TodoContext.Provider>
);
} Notes
- Congratulations on completing the React course! You now have the skills to build modern, interactive web applications. Keep practicing by building more projects and exploring the React ecosystem.
