前兩天我們逐漸完善我們的清單小程式,越來越接近todo list的雛型了。然而,目前的程式仍僅僅只有新增的功能,沒辦法刪除,因此,今天要來為他加上刪除功能。
如果要刪除某個在陣列中的項目,一般可能是用pop
或shift
刪除最後一個或第一個項目,但是若是要刪除特定的項目,就需要迴圈來處理了。要刪除特定項目,可以使用Array的filter
方法處理。
舉個例子,我想要刪除下面陣列的”a”
:
let list = [a, b, c, d, e];
list = list.filter(element => element !== “a”);
console.log(list)
// result: [b, c, d, e]
接著把這個方法放入清單小程式中:
const List = ({item, setItem})=>{
const deleteHandler = (e)=>{
// 避免a標籤的預設行為
e.preventDefault();
// 選取span標籤
const span = e.target.parentElement.children[0];
// filter
const newItem = item.filter(element=> element !== span.innerText);
//更新state
setItem(newItem);
}
// 用span標籤包住內容,方便選取
const list = item.map(i=>(
const id = uuidv4();
return (
<li key={id}><span>{i}</span><a href=”” style={{marginLeft: "1.5rem"}} onClick={deleteHandler}>delete</a></li>
)
))
return (
<ul>
{list}
</ul>
)
}
這樣就能做出簡單的刪除功能了。
然而,上面的作法有個問題:當有項目內容一樣時會一起被刪掉,這樣跟我們期望的結果不太一樣。要避免這個狀況,可以使用我們昨天介紹的uuid
去處理。
為了只刪除我們想刪除的,必須給清單元素加上獨一無二的”特徵”,供我們辨識。昨天有提到類似的東西:key
,然而key
不能直接使用,也不能當作props,因此需要將key的值傳入別的屬性中,方便我們取用。這邊我們修改一下,在新增項目時就新增id:
const Input = ({input, setInput, item, setItem})=>{
const inputHandler = (e)=>{
setInput(e.target.value);
}
const clickHandler = (e)=>{
// 新增id,以object形式更新至state
setItem([...item, {input, id: uuidv4()}]);
setInput("")
}
return (
<div>
<input type="text" onChange={inputHandler} value={input}/>
<button onClick={clickHandler}>新增</button>
</div>
)
}
在List
中使用item
中的內容與id,把id傳遞給key
及HTML屬性id
:
const list = item.map(i=>(
const {id, input} = i;
return (
<li key={id} id={id}><span>{input}</span><a href=”” style={{marginLeft: "1.5rem"}} onClick={deleteHandler}>delete</a></li>
)
))
然後刪除時不比對內容,而是比對id
:
const deleteHandler = (e)=>{
e.preventDefault();
// 選取li標籤
const li = e.target.parentElement;
// filter
const newItem = item.filter(element=> element.id !== li.id);
//更新state
setItem(newItem);
}
這樣就可以僅刪除指定的項目,而不會刪除到其他東西,讓這個清單小程式可操作性更高!