如何使用 React 删除列表项(功能组件)

Posted

技术标签:

【中文标题】如何使用 React 删除列表项(功能组件)【英文标题】:How to delete a list item with React (function component) 【发布时间】:2021-12-11 07:49:35 【问题描述】:

只是在做一个简单的练习清单,我希望能够点击我清单上的一个项目来删除它。我想我已经很接近了,但无法弄清楚如何从单击的 li 中获取某种数据以将其与我的数组进行比较。

App.js

import  useState  from "react";
import "./App.css";
import Newtodo from "./NewTodo/NewTodo";
import TodoList from "./TodoList/TodoList";

let INITIAL_TODOS = [
   id: "e1", title: "Set up meeting", date: new Date(2021, 0, 14), index: 0 ,
  
    id: "e2",
    title: "Doctor appointment",
    date: new Date(2021, 2, 14),
    index: 1,
  ,
   id: "e3", title: "Work on project", date: new Date(2021, 1, 22), index: 2 ,
   id: "e4", title: "Update resume", date: new Date(2021, 6, 14), index: 3 ,
];

const App = () => 
  const [todos, setTodos] = useState(INITIAL_TODOS);

  const deleteItem = (e) => 
    const newTodos = todos.filter((item) => item.index !== 1 /*This works properly with a hardcoded value(1) but how can this be done dynamically as e doesn't seem to have anything useful within it (like e.target.value)*/);
    setTodos(newTodos);
  ;

  return (
    <div className="App">
      <Newtodo />
      <TodoList items=todos handleDelete=deleteItem />
    </div>
  );
;

export default App;

TodoList.js

import "./TodoList.css";
import Todo from "./Todo";

const TodoList = (props) => 
  return (
    <div className="todo-list">
      <ul>
        props.items.map((todo, i) => (
          <Todo
            index=i
            key=todo.id
            title=todo.title
            date=todo.date
            handleDelete=props.handleDelete
          />
        ))
      </ul>
    </div>
  );
;

export default TodoList;

Todo.js

import "./Todo.css";

const Todo = (props) => 
  const month = props.date.toLocaleString("en-US",  month: "long" );
  const day = props.date.toLocaleString("en-US",  day: "2-digit" );
  const year = props.date.getFullYear();

  return (
    <li onClick=props.handleDelete className="todo-item">
      <h2>props.title</h2>
      <span>
        day, month, year
      </span>
    </li>
  );
;

export default Todo;

任何帮助或指导将不胜感激!

【问题讨论】:

您必须将idTodo 组件传递给其父组件。 【参考方案1】:

您需要传递要删除的元素的索引。在删除处理程序中,按索引等于传递的索引

的元素过滤
const deleteItem = (index) => 
  setTodos(todos => todos.filter((item, i) => i !== index));
;

在映射中

const TodoList = (props) => 
  return (
    <div className="todo-list">
      <ul>
        props.items.map((todo, i) => (
          <Todo
            index=i
            key=todo.id
            title=todo.title
            date=todo.date
            handleDelete=() => props.handleDelete(i)
          />
        ))
      </ul>
    </div>
  );
;

改用id 属性可能会更好。

const deleteItem = (id) => 
  setTodos(todos => todos.filter((item) => item.id !== id));
;

...

const TodoList = (props) => 
  return (
    <div className="todo-list">
      <ul>
        props.items.map((todo, i) => (
          <Todo
            index=i
            key=todo.id
            title=todo.title
            date=todo.date
            handleDelete=() => props.handleDelete(todo.id)
          />
        ))
      </ul>
    </div>
  );
;

为了避免子组件中的匿名回调,将handleDelete声明为柯里化函数。

const deleteItem = (id) => () => 
  setTodos(todos => todos.filter((item) => item.id !== id));
;

...

const TodoList = (props) => 
  return (
    <div className="todo-list">
      <ul>
        props.items.map((todo, i) => (
          <Todo
            index=i
            key=todo.id
            title=todo.title
            date=todo.date
            handleDelete=props.handleDelete(todo.id)
          />
        ))
      </ul>
    </div>
  );
;

【讨论】:

“为了避免匿名回调” 请注意,柯里化函数仍然返回匿名回调,所以它只是解决了问题,最终可能会变得更糟,性能-wise(重新渲染 Todoli 标记)。 我仍然赞成您对id 建议的回答以及正确使用设置器回调表单,而不是像接受的回答所建议的那样使用当前(可能已过时)状态。【参考方案2】:

首先你需要将你的 todo id 传递给句柄 delete 然后你可以在那里访问 id

 props.items.map((todo, i) => (
          <Todo
            index=i
            key=todo.id
            title=todo.title
            date=todo.date
            handleDelete=()=> props.handleDelete(todo.id)
          />
        ))

您在此处访问 id

  const deleteItem = (todoId) => 
     const newTodos = todos.filter((item) => item.id !== todoId;
    setTodos(newTodos);
  ;

【讨论】:

非常感谢,工作就像一个魅力。我会将其标记为已解决! :)【参考方案3】:

在 Todo.js 中添加 data-index 属性

<li data-index=props.index onClick=props.handleDelete className="todo-item">
  <h2>props.title</h2>
  <span>
   day, month, year
  </span>
</li>

并在deleteTodo删除它

const deleteItem = (e) => 
    const newTodos = todos.filter((item) => +item.index !== +e.currentTarget.dataset.index)
    setTodos(newTodos);
  ;

【讨论】:

以上是关于如何使用 React 删除列表项(功能组件)的主要内容,如果未能解决你的问题,请参考以下文章

React Native:如何正确地将 renderItem 项传递给 FlatList,以便它们可以在另一个组件中呈现?

列表项没有正确删除(反应)

如何从不是父或子的另一个组件更改功能组件的状态?

使用 react 功能组件添加和删除两个集合

使用 react 功能组件添加和删除两个集合

使用功能组件/挂钩从 React 中的数组中删除特定项目