typecode
ReactTodo App/TodoApp.tsx
1import { useReducer, useContext, createContext, ReactNode } from "react"
2
3interface Todo {
4 id: number
5 text: string
6 completed: boolean
7}
8
9type Action =
10 | { type: "ADD"; text: string }
11 | { type: "TOGGLE"; id: number }
12 | { type: "DELETE"; id: number }
13 | { type: "CLEAR_COMPLETED" }
14
15function todoReducer(state: Todo[], action: Action): Todo[] {
16 switch (action.type) {
17 case "ADD":
18 return [...state, { id: Date.now(), text: action.text, completed: false }]
19 case "TOGGLE":
20 return state.map((t) =>
21 t.id === action.id ? { ...t, completed: !t.completed } : t
22 )
23 case "DELETE":
24 return state.filter((t) => t.id !== action.id)
25 case "CLEAR_COMPLETED":
26 return state.filter((t) => !t.completed)
27 }
28}
29
30const TodoContext = createContext<{
31 todos: Todo[]
32 dispatch: React.Dispatch<Action>
33} | null>(null)
34
35function useTodos() {
36 const ctx = useContext(TodoContext)
37 if (!ctx) throw new Error("useTodos must be used within TodoProvider")
38 return ctx
39}
40
41function TodoProvider({ children }: { children: ReactNode }) {
42 const [todos, dispatch] = useReducer(todoReducer, [])
43 return (
44 <TodoContext.Provider value={{ todos, dispatch }}>
45 {children}
46 </TodoContext.Provider>
47 )
48}
49
50function TodoItem({ todo }: { todo: Todo }) {
51 const { dispatch } = useTodos()
52 return (
53 <li className={todo.completed ? "completed" : ""}>
54 <span onClick={() => dispatch({ type: "TOGGLE", id: todo.id })}>
55 {todo.text}
56 </span>
57 <button onClick={() => dispatch({ type: "DELETE", id: todo.id })}>
58 Delete
59 </button>
60 </li>
61 )
62}
63
64function TodoList() {
65 const { todos, dispatch } = useTodos()
66 const remaining = todos.filter((t) => !t.completed).length
67
68 return (
69 <div>
70 <ul>
71 {todos.map((todo) => (
72 <TodoItem key={todo.id} todo={todo} />
73 ))}
74 </ul>
75 <p>{remaining} items remaining</p>
76 <button onClick={() => dispatch({ type: "CLEAR_COMPLETED" })}>
77 Clear completed
78 </button>
79 </div>
80 )
81}
82
83export default function App() {
84 return (
85 <TodoProvider>
86 <h1>Todo App</h1>
87 <TodoList />
88 </TodoProvider>
89 )
90}
0WPM
100%Accuracy
00:00Time
0%
Progress