Created
March 31, 2020 17:17
-
-
Save marekdano/ac2bd147c8144df9500e9e02f8753ab2 to your computer and use it in GitHub Desktop.
Simple Todo list app using React Hooks with CRUD functions edit, delete a todo and/or mark a todo as done.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState, useRef, useEffect } from "react"; | |
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | |
import { faCheck } from "@fortawesome/free-solid-svg-icons"; | |
import { library } from "@fortawesome/fontawesome-svg-core"; | |
import "./styles.css"; | |
library.add(faCheck); | |
/* | |
Todo app structure | |
TodoApp | |
- TodoHeader | |
- TodoList | |
- TodoListItem #1 | |
- TodoListItem #2 | |
... | |
- TodoListItem #N | |
- TodoForm | |
*/ | |
const TodoList = props => ( | |
<ul className="list-group"> | |
{props.items.map(item => ( | |
<TodoListItem | |
key={item.index} | |
item={item} | |
itemIndex={item.index} | |
removeItem={props.removeItem} | |
markTodoDone={props.markTodoDone} | |
updateItemValue={props.updateItemValue} | |
/> | |
))} | |
</ul> | |
); | |
const TodoListItem = ({ | |
item, | |
itemIndex, | |
removeItem, | |
markTodoDone, | |
updateItemValue | |
}) => { | |
const [editMode, setEditMode] = useState(false); | |
const [inputValue, setInputValue] = useState(item.value); | |
const handleEditValue = () => { | |
setEditMode(false); | |
updateItemValue(inputValue, itemIndex); | |
}; | |
const keyPress = e => { | |
if (e.key === "Enter") { | |
handleEditValue(); | |
} | |
}; | |
return ( | |
<li className="list-group-item"> | |
<div className={item.done ? "done" : "undone"}> | |
<FontAwesomeIcon | |
className="icon" | |
icon={faCheck} | |
onClick={() => markTodoDone(itemIndex)} | |
/> | |
<span onClick={() => setEditMode(true)}> | |
{editMode ? ( | |
<input | |
type="text" | |
value={inputValue} | |
onChange={e => setInputValue(e.target.value)} | |
onBlur={handleEditValue} | |
onKeyPress={keyPress} | |
autoFocus | |
/> | |
) : ( | |
item.value | |
)} | |
</span> | |
<button | |
type="button" | |
className="close" | |
onClick={() => removeItem(itemIndex)} | |
> | |
× | |
</button> | |
</div> | |
</li> | |
); | |
}; | |
const TodoForm = ({ addItem }) => { | |
const inputEl = useRef(null); | |
useEffect(() => { | |
inputEl.current.focus(); | |
}, []); | |
const onSubmit = event => { | |
event.preventDefault(); | |
let newInputValue = inputEl.current.value; | |
if (newInputValue) { | |
addItem({ newItemValue: newInputValue }); | |
inputEl.current.value = ""; | |
} | |
}; | |
return ( | |
<form onSubmit={onSubmit} className="form-inline"> | |
<input | |
type="text" | |
ref={inputEl} | |
className="form-control" | |
placeholder="add a new todo..." | |
/> | |
<button type="submit" className="btn btn-light"> | |
Add | |
</button> | |
</form> | |
); | |
}; | |
const TodoHeader = () => <h1>Todo list</h1>; | |
const TodoApp = props => { | |
const [todoItems, setTodoItems] = useState(props.initItems); | |
const [id, setId] = useState(props.initItems.length); | |
const addItem = newTodoItem => { | |
const newId = id + 1; | |
setTodoItems([ | |
...todoItems, | |
{ | |
index: newId, | |
value: newTodoItem.newItemValue, | |
done: false | |
} | |
]); | |
setId(newId); | |
}; | |
const removeItem = itemIndex => { | |
const updatedTodoItems = todoItems.filter(item => item.index !== itemIndex); | |
setTodoItems(updatedTodoItems); | |
}; | |
const markTodoDone = itemIndex => { | |
const updatedTodoItems = todoItems.map(item => | |
item.index === itemIndex | |
? { | |
...item, | |
done: !item.done | |
} | |
: item | |
); | |
setTodoItems(updatedTodoItems); | |
}; | |
const updateItemValue = (value, itemIndex) => { | |
const updatedTodoItems = todoItems.map(item => | |
item.index === itemIndex | |
? { | |
...item, | |
value | |
} | |
: item | |
); | |
setTodoItems(updatedTodoItems); | |
}; | |
return ( | |
<div id="main"> | |
<TodoHeader /> | |
<TodoList | |
items={todoItems} | |
removeItem={removeItem} | |
markTodoDone={markTodoDone} | |
updateItemValue={updateItemValue} | |
/> | |
<TodoForm addItem={addItem} /> | |
</div> | |
); | |
}; | |
export default TodoApp; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Demo here https://codesandbox.io/s/boring-browser-plm65