我正在尝试制作一个待办事项应用程序,其中我在删除元素时创建了删除功能,该元素被成功删除但是一旦我在输入框中键入我就会收到此错误。 无法在“节点”上执行“removeChild”:要删除的节点不是该节点的子节点。
import { React, useState } from 'react'
import "./todo.css"
function Todo() {
const [value, setValue] = useState("") //input value
const [items, setitems] = useState([]) //items to be added
function handleClick() {
// Adding items in a item array
setitems(items.concat(value))
setValue("")
}
function handleChange(e) {
// Fetching input value
setValue(e.target.value)
}
return (
<>
<div className='container'>
<h1 id='mainhead'>Todo App</h1>
</div>
<div className='container1'>
<input onChange={handleChange} value={value} placeholder='Enter a task' type="text" />
<button onClick={handleClick}>Add Item</button>
</div>
{/* mapping all the items */}
{items.length !== 0 ? items.map((e) => {
return <div className='item' key={e}><label>Task {items.indexOf(e) + 1}:</label> {e}
<button style={{float:"right" , backgroundColor:"red" , color:"white" , width:"80px" , height:"30px"}} onClick={()=>{
const child = document.getElementById("delete" + items.indexOf(e)) // accessing child
console.log(child)
child.parentElement.remove() //Deleting parent element
items.splice(items.indexOf(e),1) //removing element from items
setitems(items) // updating items
}} id = {"delete" + items.indexOf(e)}>Delete</button> </div>
})
: null}
</>
)
}
export default Todo
我尝试了一切,但没有任何效果可以帮助我处理这个错误
不是直接更改DOM,而是使用状态来管理项目。要从列表中删除项目,您可以过滤该项目并设置新状态。
function handleDelete(index) {
// Filter the items array and remove the item at the given index
const newItems = items.filter((_, i) => i !== index);
setItems(newItems);
}
用handleDelete() 函数替换Delete 按钮 的onClick 处理程序。所以渲染图会这样变化:
{/* mapping all the items */}
{
items.length !== 0
? items.map((e, index) => {
return (
<div className="item" key={index}>
<label>Task {index + 1}:</label> {e}
<button
style={{
float: "right",
backgroundColor: "red",
color: "white",
width: "80px",
height: "30px",
}}
onClick={() => handleDelete(index)}
id={"delete" + index}
>
Delete
</button>
</div>
);
})
: null;
}
顺便说一句: 上面的代码使用索引进行过滤并作为虚拟 DOM 元素键,只是为了尽可能接近您的示例。为元素设置唯一 ID 是一种很好的做法。这可以提高性能,帮助避免错误,并使调试更容易。
您基本上拥有组件所需的所有位 - 最重要的是保存待办事项的状态。必要的更改是当您单击任何删除按钮时调用的处理程序应该简单地
filter
从状态中取出正确的待办事项。
促进这一点的最好方法是确保您添加到状态的待办事项是 objects,并且每个对象都有一个 id。然后将该 id 添加到 data 属性,以便在调用处理程序时可以使用该 id 从状态中过滤正确的对象。
我已经对您的代码进行了一些尝试 - 重命名,并将待办事项放在表格中 - 但希望评论会有所帮助。
const { useState } = React;
function Todos() {
const [ text, setText ] = useState('');
const [ todos, setTodos ] = useState([]);
// You should be setting state without
// mutating the array. Here I'm adding a new
// object with an id to the state (we pass in
// the previous state, and then add the new object
// to that
function handleAdd(e) {
setTodos(prev => {
return [
...prev,
{ id: prev.length + 1, text }
];
});
setText('');
}
function handleChange(e) {
setText(e.target.value);
}
// You can use the id from the element's dataset
// to allow you to filter out that object from the todos
// array, and then set the todos state with that
// filtered array. Note the id from the dataset will be a
// string so we need to coerce it to a number before we
// do a strict equality comparison
function handleDelete(e) {
const { dataset: { id } } = e.target;
const filtered = todos.filter(todo => Number(id) !== todo.id);
setTodos(filtered);
}
// For this example I've put the todos in a table
// for easier visualisation. You'll note that the todo
// id is added to a data attribute on the each delete button
// so that it can be used in the delete handler
return (
<main>
<header>
<h1>Todo App</h1>
</header>
<section className="container1">
<input onChange={handleChange} value={text} placeholder="Enter a task" type="text" />
<button onClick={handleAdd}>Add Item</button>
</section>
<table>
<tbody>
{todos.length ? todos.map(todo => {
return (
<tr className="item" key={todo.id}>
<td class="id">{todo.id}</td>
<td class="text">{todo.text}</td>
<td>
<button
data-id={todo.id}
class="delete"
onClick={handleDelete}
>Delete
</button>
</td>
</tr>
);
}) : null}
</tbody>
</table>
</main>
);
}
ReactDOM.render(
<Todos />,
document.getElementById('react')
);
table { width: 80%; margin-top: 1em; }
td.id { width: 10%; }
td.text { width: 100%; }
td.delete { float: right; }
.item { display: flex; flex-direction: row; border: 1px solid lightgray; }
.delete { background-color: salmon; margin-left: 1em; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>