A modern, interactive To-Do List application built with React, featuring state management with useReducer, local storage persistence, and a clean UI.
- ✅ Add, delete, and toggle todos
- ✅ Filter todos by status (All, Active, Completed)
- ✅ Active tasks counter
- ✅ Clear all completed tasks at once
- ✅ Persistent storage using localStorage
- ✅ Input validation with visual feedback
- ✅ Responsive design for mobile and desktop
- ✅ Clean, modern UI with SCSS
- Node.js (v14 or higher)
- npm or yarn
- Clone the repository:
git clone <repository-url>
cd todo-app- Install dependencies:
npm install- Start the development server:
npm startThe app will open at http://localhost:3000
npm run buildThis creates an optimized production build in the build folder.
I chose useReducer over useState for managing the todo list state because:
- Scalability: As the app grows, reducer pattern makes state updates more predictable
- Complex state logic: Multiple actions (add, delete, toggle, clear) are easier to manage in a reducer
- Better testing: Pure reducer functions are easier to test independently
- Clear action types: Using action constants makes the code more maintainable
Created a custom useLocalStorage hook to:
- Separate persistence logic from component logic
- Make the hook reusable across the app
- Handle localStorage errors gracefully
- Prevent initial state overwrite using
useRef
- useCallback: Wrapped event handlers to prevent unnecessary re-renders of child components
- useMemo: Used for filtering todos and calculating counts to avoid expensive recalculations on every render
- React.memo: Could be added to TodoItem if performance issues arise with large lists
App (Main container, state management)
├── TodoForm (Input with validation)
├── TodoList (Displays filtered todos)
│ └── TodoItem (Individual todo with actions)
└── TodoFilters (Filter buttons and stats)
This structure provides:
- Clear separation of concerns
- Reusable components
- Easy to test individual pieces
- Scalable architecture
Used SCSS instead of plain CSS for:
- Variables for consistent theming
- Nesting for cleaner, more maintainable styles
- Mixins potential for repeated patterns
- Better organization with component-specific stylesheets
Each todo item contains:
{
id: timestamp, // Unique identifier
text: string, // Todo content
completed: boolean, // Completion status
createdAt: ISO string // Creation timestamp
}Using timestamp as ID is sufficient for this app since:
- No concurrent users
- Simple client-side only app
- Provides chronological ordering
- React 19.2.0
- React Hooks (useState, useReducer, useCallback, useMemo, useEffect, useRef)
- SCSS for styling
- localStorage API
- Create React App
If I had more time, I would add:
- Edit todo functionality (double-click to edit)
- Drag and drop to reorder todos
- Due dates and priorities
- Categories/tags
- Dark mode toggle
- Unit tests with React Testing Library
- TypeScript for better type safety