Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9239524

Browse files
useReducer & useContext: Todo-app
1 parent 909aa3d commit 9239524

File tree

10 files changed

+111
-39
lines changed

10 files changed

+111
-39
lines changed

‎todos-app/src/EditTodo.js‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
import React from 'react';
1+
import React, {useContext} from 'react';
2+
import {DispatchContext} from './contexts/todos.context';
23
import useInputState from './hooks/useInputState';
34
import TextField from '@material-ui/core/TextField';
45

5-
function EditTodo({id, task, editTodo,toggle}){
6+
function EditTodo({id, task, toggle}){
67
const [value, handleChange, reset] = useInputState(task);
8+
const dispatch = useContext(DispatchContext);
79
return(
810
<form onSubmit={e=>{
911
e.preventDefault();
10-
editTodo(id,value);
12+
dispatch({type: "EDIT",id:id,task:value});
1113
reset();
1214
toggle();
1315
}

‎todos-app/src/TodoForm.js‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
import React from 'react';
1+
import React,{useContext} from 'react';
22
import Paper from '@material-ui/core/Paper';
33
import TextField from '@material-ui/core/TextField';
44
import useInputState from './hooks/useInputState';
5+
import {DispatchContext} from './contexts/todos.context';
56

6-
function TodoForm({addTodo}){
7+
function TodoForm(){
78
const [value, handleChange, reset] = useInputState("");
9+
const dispatch = useContext(DispatchContext);
810
return(
911
<Paper style={{margin: "1rem 0", padding: "0 1rem"}}>
1012
<form onSubmit={e=>{
1113
e.preventDefault();
12-
addTodo(value);
14+
dispatch({type: "ADD",task: value});
1315
reset();
1416
}
1517
}>

‎todos-app/src/TodoItem.js‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import React from 'react';
1+
import React,{useContext,memo} from 'react';
22
import useToggle from './hooks/useToggle';
3+
import {DispatchContext} from './contexts/todos.context';
34
import EditTodo from './EditTodo';
45
import ListItem from '@material-ui/core/ListItem';
56
import ListItemText from '@material-ui/core/ListItemText';
@@ -8,18 +9,20 @@ import IconButton from '@material-ui/core/IconButton';
89
import DeleteIcon from '@material-ui/icons/Delete';
910
import EditIcon from '@material-ui/icons/Edit';
1011
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
11-
function TodoItem({id, task, completed, deleteTodo, toggleComplete, editTodo}){
12+
function TodoItem({id, task, completed}){
1213
const [isEditing, toggle] = useToggle(false);
14+
const dispatch = useContext(DispatchContext);
15+
console.log("TODO Rerendering", id);
1316
return(
1417
<ListItem style={{height: "64px"}}>
15-
{isEditing ? <EditTodo editTodo={editTodo}id={id} task={task} toggle={toggle}/> : (
18+
{isEditing ? <EditTodo id={id} task={task} toggle={toggle}/> : (
1619
<>
17-
<Checkbox tabIndex={-1} checked={completed} onClick={() => toggleComplete(id)}/>
20+
<Checkbox tabIndex={-1} checked={completed} onClick={() => dispatch({type:"TOGGLE",id: id})}/>
1821
<ListItemText style={{textDecoration: completed ? 'line-through': 'none'}}>
1922
{task}
2023
</ListItemText>
2124
<ListItemSecondaryAction>
22-
<IconButton aria-label='Delete' onClick={() => deleteTodo(id)}>
25+
<IconButton aria-label='Delete' onClick={() => dispatch({type:"DELETE",id: id})}>
2326
<DeleteIcon/>
2427
</IconButton>
2528
<IconButton aria-label='Edit' onClick={toggle}>
@@ -33,4 +36,4 @@ function TodoItem({id, task, completed, deleteTodo, toggleComplete, editTodo}){
3336
)
3437
}
3538

36-
export default TodoItem;
39+
export default memo(TodoItem);

‎todos-app/src/TodoList.js‎

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,25 @@
1-
import React from 'react';
1+
import React,{useContext} from 'react';
22
import TodoItem from './TodoItem';
3+
import {TodosContext} from './contexts/todos.context';
34
import Divider from '@material-ui/core/Divider';
45
import Paper from '@material-ui/core/Paper';
56
import List from '@material-ui/core/List';
6-
function TodoList(props){
7-
const todos = props.todos.map((todo, i) => (
7+
function TodoList(){
8+
const todos = useContext(TodosContext);
9+
const todoList = todos.map((todo, i) => (
810
<div key={todo.id}>
911
<TodoItem
10-
task={todo.task}
11-
id={todo.id}
12+
{...todo}
1213
key={todo.id}
13-
completed={todo.completed}
14-
deleteTodo={props.deleteTodo}
15-
editTodo={props.editTodo}
16-
toggleComplete={props.toggleComplete}
1714
/>
18-
{i < props.todos.length-1 && <Divider/>}
15+
{i < todos.length-1 && <Divider/>}
1916
</div>
2017
));
2118
if(todos.length)
2219
return(
2320
<Paper>
2421
<List>
25-
{todos}
22+
{todoList}
2623
</List>
2724
</Paper>
2825
);

‎todos-app/src/Todos.js‎

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import React,{useEffect} from 'react';
2-
import useTodoState from './hooks/useTodoState';
1+
import React from 'react';
2+
import {TodosProvider} from './contexts/todos.context';
33
import TodoList from './TodoList';
44
import TodoForm from './TodoForm';
55
import Grid from '@material-ui/core/Grid';
@@ -8,16 +8,11 @@ import Toolbar from '@material-ui/core/Toolbar';
88
import Typography from '@material-ui/core/Typography';
99

1010
function Todos(){
11-
const InitialTodos = JSON.parse(window.localStorage.getItem("todos") || []);
1211
/*const InitialTodos = [
1312
{id: 1, task: "Walk the Dog", completed: true},
1413
{id: 2, task: "Buy Groceries", completed: false},
1514
{id: 3, task: "Clean the Table", completed: true}
1615
];*/
17-
const {todos, addTodo, deleteTodo, toggleComplete, editTodo} = useTodoState(InitialTodos);
18-
useEffect(() => {
19-
window.localStorage.setItem("todos", JSON.stringify(todos));
20-
}, [todos]);
2116
return(
2217
<div>
2318
<AppBar position="static">
@@ -27,13 +22,10 @@ function Todos(){
2722
</AppBar>
2823
<Grid container justify="center" style={{marginTop: "1rem"}}>
2924
<Grid item xs={11} md={8} lg={4}>
30-
<TodoForm addTodo={addTodo}/>
31-
<TodoList
32-
todos={todos}
33-
deleteTodo={deleteTodo}
34-
toggleComplete={toggleComplete}
35-
editTodo={editTodo}
36-
/>
25+
<TodosProvider>
26+
<TodoForm/>
27+
<TodoList/>
28+
</TodosProvider>
3729
</Grid>
3830
</Grid>
3931
</div>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React, {createContext, useReducer} from 'react';
2+
import {useLocalStorageReducer} from './../hooks/useLocalStorageReducer';
3+
import todoReducer from './../reducers/todo.reducer';
4+
5+
export const TodosContext = createContext();
6+
export const DispatchContext = createContext();
7+
8+
const defaultTodo = [
9+
{id: 1, task: "Read Moby Dick", completed:false}
10+
];
11+
12+
export function TodosProvider(props){
13+
const [todos, dispatch] = useLocalStorageReducer("todos", defaultTodo, todoReducer);
14+
return(
15+
<TodosContext.Provider value={todos}>
16+
<DispatchContext.Provider value={dispatch}>
17+
{props.children}
18+
</DispatchContext.Provider>
19+
</TodosContext.Provider>
20+
)
21+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import {useReducer, useEffect} from 'react';
2+
3+
function useLocalStorageReducer(key, defaultVal, reducer){
4+
const [state, dispatch] = useReducer(reducer, defaultVal, ()=>{
5+
let value;
6+
try{
7+
value = JSON.parse(window.localStorage.getItem(key) || String(defaultVal));
8+
}catch(e){
9+
value = defaultVal;
10+
}
11+
return value;
12+
})
13+
useEffect(() => {
14+
window.localStorage.setItem(key, JSON.stringify(state));
15+
}, [state]);
16+
return [state, dispatch];
17+
}
18+
19+
export {useLocalStorageReducer};
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import {useState, useEffect} from 'react';
2+
3+
function useLocalStorageState(key, defaultVal){
4+
const [state, setState] = useState(()=>{
5+
let value;
6+
try{
7+
value = JSON.parse(window.localStorage.getItem(key) || String(defaultVal));
8+
}catch(e){
9+
value = defaultVal;
10+
}
11+
return value;
12+
});
13+
useEffect(() => {
14+
window.localStorage.setItem(key, JSON.stringify(state));
15+
}, [state]);
16+
return [state, setState];
17+
}
18+
19+
export {useLocalStorageState};

‎todos-app/src/hooks/useTodoState.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import {useState}from 'react';
1+
import {useLocalStorageState}from './useLocalStorageState';
22
import uuid from 'uuid/v4';
33
export default InitialTodos => {
4-
const [todos, setTodos] = useState(InitialTodos);
4+
const [todos, setTodos] = useLocalStorageState("todos",InitialTodos);
55
return {
66
todos,
77
addTodo: (newTodo) => {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import uuid from "uuid/v4";
2+
const reducer = (state, action) => {
3+
switch(action.type){
4+
case "ADD":
5+
return [...state, {id: uuid(), task: action.task, completed: false}]
6+
case "DELETE":
7+
return state.filter(todo => todo.id !== action.id);
8+
case "TOGGLE":
9+
return state.map(todo => todo.id === action.id ? {...todo, completed: !todo.completed} : todo);
10+
case "EDIT":
11+
return state.map(todo => todo.id === action.id ? {...todo, task: action.task} : todo);
12+
default:
13+
return state;
14+
}
15+
}
16+
17+
export default reducer;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /