|
1 | | -import React, { |
2 | | - useState, |
3 | | - useReducer, |
4 | | - useContext, |
5 | | - createContext, |
6 | | -} from 'react'; |
7 | | - |
8 | | -import uuid from 'uuid/v4'; |
9 | | - |
10 | | -const DispatchContext = createContext(null); |
11 | | - |
12 | | -const initalTodos = [ |
13 | | - { |
14 | | - id: 'a', |
15 | | - task: 'Learn React', |
16 | | - complete: true, |
17 | | - }, |
18 | | - { |
19 | | - id: 'b', |
20 | | - task: 'Learn Firebase', |
21 | | - complete: true, |
22 | | - }, |
23 | | - { |
24 | | - id: 'c', |
25 | | - task: 'Learn GraphQL', |
26 | | - complete: false, |
27 | | - }, |
28 | | -]; |
29 | | - |
30 | | -const todoReducer = (state, action) => { |
31 | | - switch (action.type) { |
32 | | - case 'DO_TODO': |
33 | | - return state.map(todo => { |
34 | | - if (todo.id === action.id) { |
35 | | - return { ...todo, complete: true }; |
36 | | - } else { |
37 | | - return todo; |
38 | | - } |
39 | | - }); |
40 | | - case 'UNDO_TODO': |
41 | | - return state.map(todo => { |
42 | | - if (todo.id === action.id) { |
43 | | - return { ...todo, complete: false }; |
44 | | - } else { |
45 | | - return todo; |
46 | | - } |
47 | | - }); |
48 | | - case 'ADD_TODO': |
49 | | - return state.concat({ |
50 | | - task: action.task, |
51 | | - id: uuid(), |
52 | | - complete: false, |
53 | | - }); |
54 | | - default: |
55 | | - return state; |
56 | | - } |
57 | | -}; |
58 | | - |
59 | | -const filterReducer = (state, action) => { |
60 | | - switch (action.type) { |
61 | | - case 'SHOW_ALL': |
62 | | - return 'ALL'; |
63 | | - case 'SHOW_COMPLETE': |
64 | | - return 'COMPLETE'; |
65 | | - case 'SHOW_INCOMPLETE': |
66 | | - return 'INCOMPLETE'; |
67 | | - default: |
68 | | - return state; |
69 | | - } |
70 | | -}; |
71 | | - |
72 | | -const App = () => { |
73 | | - const [todos, todosDispatch] = useReducer(todoReducer, initalTodos); |
74 | | - const [filter, filterDispatch] = useReducer(filterReducer, 'ALL'); |
75 | | - |
76 | | - // Global Dispatch Function |
77 | | - const dispatch = action => |
78 | | - [todosDispatch, filterDispatch].forEach(fn => fn(action)); |
79 | | - |
80 | | - const filteredTodos = todos.filter(todo => { |
81 | | - if (filter === 'ALL') { |
82 | | - return true; |
83 | | - } |
84 | | - |
85 | | - if (filter === 'COMPLETE' && todo.complete) { |
86 | | - return true; |
87 | | - } |
88 | | - |
89 | | - if (filter === 'INCOMPLETE' && !todo.complete) { |
90 | | - return true; |
91 | | - } |
92 | | - |
93 | | - return false; |
94 | | - }); |
95 | | - |
96 | | - return ( |
97 | | - <DispatchContext.Provider value={dispatch}> |
98 | | - <Filter /> |
99 | | - <TodoList todos={filteredTodos} /> |
100 | | - <AddTodo /> |
101 | | - </DispatchContext.Provider> |
102 | | - ); |
103 | | -}; |
104 | | - |
105 | | -const AddTodo = () => { |
106 | | - const [task, setTask] = useState(''); |
107 | | - |
108 | | - const dispatch = useContext(DispatchContext); |
109 | | - |
110 | | - const handleSubmit = event => { |
111 | | - if (task) { |
112 | | - dispatch({ type: 'ADD_TODO', task }); |
113 | | - } |
114 | | - |
115 | | - setTask(''); |
116 | | - |
117 | | - event.preventDefault(); |
118 | | - }; |
119 | | - |
120 | | - const handleChange = event => setTask(event.target.value); |
121 | | - |
122 | | - return ( |
123 | | - <form onSubmit={handleSubmit}> |
124 | | - <input type="text" value={task} onChange={handleChange} /> |
125 | | - <button type="submit">Add Todo</button> |
126 | | - </form> |
127 | | - ); |
128 | | -}; |
129 | | - |
130 | | -const TodoList = ({ todos }) => ( |
131 | | - <ul> |
132 | | - {todos.map(todo => ( |
133 | | - <TodoItem key={todo.id} todo={todo} /> |
134 | | - ))} |
135 | | - </ul> |
136 | | -); |
137 | | - |
138 | | -const TodoItem = ({ todo }) => { |
139 | | - const dispatch = useContext(DispatchContext); |
140 | | - |
141 | | - const handleChange = () => |
142 | | - dispatch({ |
143 | | - type: todo.complete ? 'UNDO_TODO' : 'DO_TODO', |
144 | | - id: todo.id, |
145 | | - }); |
146 | | - |
147 | | - return ( |
148 | | - <li> |
149 | | - <label> |
150 | | - <input |
151 | | - type="checkbox" |
152 | | - checked={todo.complete} |
153 | | - onChange={handleChange} |
154 | | - /> |
155 | | - {todo.task} |
156 | | - </label> |
157 | | - </li> |
158 | | - ); |
159 | | -}; |
160 | | - |
161 | | -const Filter = () => { |
162 | | - const dispatch = useContext(DispatchContext); |
163 | | - |
164 | | - const handleShowAll = () => { |
165 | | - dispatch({ type: 'SHOW_ALL' }); |
166 | | - }; |
167 | | - |
168 | | - const handleShowComplete = () => { |
169 | | - dispatch({ type: 'SHOW_COMPLETE' }); |
170 | | - }; |
171 | | - |
172 | | - const handleShowIncomplete = () => { |
173 | | - dispatch({ type: 'SHOW_INCOMPLETE' }); |
174 | | - }; |
175 | | - |
176 | | - return ( |
177 | | - <div> |
178 | | - <button type="button" onClick={handleShowAll}> |
179 | | - Show All |
180 | | - </button> |
181 | | - <button type="button" onClick={handleShowComplete}> |
182 | | - Show Complete |
183 | | - </button> |
184 | | - <button type="button" onClick={handleShowIncomplete}> |
185 | | - Show Incomplete |
186 | | - </button> |
187 | | - </div> |
188 | | - ); |
189 | | -}; |
190 | | - |
191 | | -export default App; |
0 commit comments