Initialize React app with TypeScript
⏱️ 1-2 hours
npm create vite@latest todo-app -- --template react-ts
cd todo-app
npm install
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -pUse Vite for faster builds
Install Tailwind CSS for styling
⚠️ Common Pitfalls:
Create TodoItem and TodoList components
⏱️ 2-3 hours
interface Todo {
id: string
text: string
completed: boolean
createdAt: Date
}export function TodoItem({ todo, onToggle, onDelete }: TodoItemProps) {
return (
<div className="flex items-center gap-2 p-4 border rounded">
<input type="checkbox" checked={todo.completed} onChange={() => onToggle(todo.id)} />
<span className={todo.completed ? "line-through" : ""}>{todo.text}</span>
<button onClick={() => onDelete(todo.id)}>Delete</button>
</div>
)
}Create a types.ts file for TypeScript interfaces
Use props destructuring in components
⚠️ Common Pitfalls:
Add CRUD operations with useState
⏱️ 2-3 hours
const [todos, setTodos] = useState<Todo[]>([])
const addTodo = (text: string) => {
const newTodo: Todo = {
id: crypto.randomUUID(),
text,
completed: false,
createdAt: new Date()
}
setTodos([...todos, newTodo])
}Use useState to manage todo list
Generate unique IDs with crypto.randomUUID()
⚠️ Common Pitfalls:
Persist todos to localStorage
⏱️ 1-2 hours
useEffect(() => {
const stored = localStorage.getItem("todos")
if (stored) {
setTodos(JSON.parse(stored))
}
}, [])
useEffect(() => {
localStorage.setItem("todos", JSON.stringify(todos))
}, [todos])Use useEffect to sync with localStorage
Handle JSON parsing errors
⚠️ Common Pitfalls:
Add filter options (All/Active/Completed)
⏱️ 1-2 hours
const filteredTodos = todos.filter(todo => {
if (filter === "active") return !todo.completed
if (filter === "completed") return todo.completed
return true
})Use state for active filter
Filter before mapping todos
⚠️ Common Pitfalls:
Add animations and deploy to Vercel
⏱️ 1-2 hours
npm run build
npm install -g vercel
vercel --prodTest production build locally first
Add loading states for better UX
⚠️ Common Pitfalls: