今天要繼續實作todolist,要讓todolist有切換已完成、未完成狀態的功能。
昨天的編輯功能出了點問題,若是在沒修改的情況下提交,由於newInput
沒東西,所以會變成空值。
今天來修正一下,將newInput
加入條件控制,並在提交後重設newInput
:
// List.js
const editedHandler=(e)=>{
const newItem = item.map(i=>{
const {id, content} = i;
// newInput要有東西才修改content
if(id === isEdit && newInput){
i.content = newInput;
return i;
}
return i;
})
// 重置newInput
setNewInput("");
setIsEdit("");
setItem(newItem);
}
由於項目要render的東西越來越多,我們把它取出來獨立成component:
// Item.js
const Item = ({content, id, setIsEdit, item, setItem})=>{
// 把deleteHandler移入這裡
const deleteHandler = (e)=>{
e.preventDefault();
// 可以取得id,直接取id
const newItem = item.filter(element=> element.id !== id);
setItem(newItem);
}
return (
<Card>
{/*…*/}
</Card>
)
}
// List.js
const List = ({item, setItem})=>{
// …
const list = item.map((i, index)=>{
const {content, id} = i;
return(
<div key={id}>
{/*將content、id、setIsEdit、item、setItem傳入Item*/}
{!(isEdit === id) ? <Item content={content} id={id} setIsEdit={setIsEdit} item={item} setItem={setItem}/> : (<InputGroup className="my-3">
<Form.Control type="text" onChange={(e)=>{setNewInput(e.target.value)}} defaultValue={content}/>
<Button onClick={editedHandler}>提交</Button>
</InputGroup>)}
</div>)
}
)
return (
<div>
{list}
</div>
)
}
接著,處理一下架構,在Item
中加入checkbox,將Card.Body
用Form.Check
component包起來:
// Item.js
<Card>
<Form.Check type="checkbox" id={`check-${id}`} className="d-flex align-items-center">
{/*加上Form.Input,才會出現checkbox*/}
<Form.Check.Input type="checkbox" className="m-0" onClick={checkHandler}/>
{/*用Form.Check.Label把整個Card.Body包起來*/}
<Form.Check.Label className="w-100">
<Card.Body id={id} className="d-flex justify-content-between">{
{/*…*/}
</Card.Body>
</Form.Check.Label>
</Form.Check>
</Card>
接下來要加上程式邏輯,一樣要用state去做。在Item
上加上isDone
的state。
// Item.js
const [isDone, setIsDone]= useState(false);
當checked時,isDone
切換成true,反之則false:
// Item.js
const checkHandler = (e)=>{
if(e.target.checked){
setIsDone(true);
}else{
setIsDone(false);
};
}
// …
<Form.Check>
<Form.Check.Input type="checkbox" className="m-0" onClick={checkHandler}/>
</Form.Check>
接著讓內容在完成時畫一條刪除線,一樣用三元運算子控制:
// Item.js
<Card.Body id={id} className="d-flex justify-content-between">
<span className={isDone ? "text-decoration-line-through" : ""}>{content}</span>
{/*…*/}
</Card.body>
這樣就能完成完成事項的效果。然而,這只是樣式改變而已,沒有真正儲存到已完成、未完成的狀態。明天會儲存已完成、未完成的內容,並且製作分頁來顯示已完成、未完成的事項。