我如何访问我点击的项目(以便我可以删除它)?

时间:2021-06-23 19:38:09

标签: javascript reactjs react-hooks

我不明白如何使用 deleteItem 函数删除我们的 items 数组中被点击的项目。

我卡住的地方是我不明白如何获取我点击的 <li> 的索引或文本,以便我可以在我的过滤器方法中使用它来返回一个新数组,而不需要被点击的项目。

我尝试使用道具,但这不起作用。我不明白 deleteItem 函数如何与 todoitem 组件及其其余部分相关联。

import React, { useState } from "react";
import ToDoItem from "./ToDoItem";

function App() {
  const [inputText, setInputText] = useState("");
  const [items, setItems] = useState([]);

  function handleChange(event) {
    const newValue = event.target.value;
    setInputText(newValue);
  }

  function addItem() {
    setItems((prevItems) => {
      return [...prevItems, inputText];
    });
    setInputText("");
  }

  function deleteItem() {
    // setItems((prevState) => {
    //   return prevState.filter(function (item) {
    //     return item === props.item;
    //   });
    // });
    // console.log(items[2]);
    console.log();
  }

  return (
    <div className="container">
      <div className="heading">
        <h1>To-Do List</h1>
      </div>
      <div className="form">
        <input onChange={handleChange} type="text" value={inputText} />
        <button onClick={addItem}>
          <span>Add</span>
        </button>
      </div>
      <div>
        <ul>
          {items.map((todoItem, index) => (
            <ToDoItem
              key={index}
              id={index}
              item={todoItem}
              deleteItem={deleteItem}
            />
          ))}
        </ul>
      </div>
    </div>
  );
}

export default App;
import React from "react";

function ToDoItem(props) {
  return <li onClick={props.deleteItem}>{props.item}</li>;
}

export default ToDoItem;

3 个答案:

答案 0 :(得分:1)

我总是这样做 - 这是一个多一点的代码,但你最终不会为每个项目都有一个单独的 delete 函数,或者必须处理抓取 DOM 树(parentNode 和朋友).

  1. 将项目索引放在数据属性上:
    <li data-item-index={props.id} ...>
    
  2. 在点击处理程序中,获取项目的索引并将其删除:
    function deleteItem(ev) {
        const itemIndex = parseInt(ev.target.dataset.itemIndex, 10);
        setItems([
            ...items.slice(0, itemIndex), 
            ...items.slice(itemIndex + 1)
        ]);
    }
    

编辑:虽然超出了这个问题的范围,但值得一提的是:

  1. 始终尽量避免 onClick={() => deleteItem(props.id)} 样式的回调,尤其是在呈现项目列表时。这些对于快速原型设计、在线示例等很有用 - 但在实际应用程序中,您几乎总是应该执行以下操作:

    const deleteItem = useCallback(() => { ... }, []);
    <li onClick={deleteItem}>...</li>
    
    <块引用>

    注意:这不是“过早优化”,它是您每次需要回调时使用的一组额外按键。

  2. 为了避免违反计算机科学的某些教条规则,您应该创建辅助函数来设置和检索值。将所有内容放在一个过于冗长的答案中:

    const setItemIdAttr = (id) => ({ 'data-item-id': id });
    const getItemIdFromAttr = (el) => parseInt(el.dataset.itemId, 10);
    
    const deleteItem = useCallback((ev) => {
        const itemIndex = getItemIdFromAttr(ev.target);
        setItems((oldItems) => [
            ...oldItems.slice(0, itemIndex), 
            ...oldItems.slice(itemIndex + 1)
        ]);
    }, []);
    
    <li {...setItemIdAttr(id)} onClick={deleteItem} ...>
    
    
    

答案 1 :(得分:0)

您可以访问使用 li 点击的 event.target 项目:

function deleteItem(event) {
    const item = event.target
    console.log("Item :", item);
    console.log("Index :", Array.from(item.parentNode.children).indexOf(item));
}

function ToDoItem(props) {
  return <li onClick={props.deleteItem}>{props.item}</li>;
}

function App() {
  const [inputText, setInputText] = React.useState("");
  const [items, setItems] = React.useState([]);

  function handleChange(event) {
    const newValue = event.target.value;
    setInputText(newValue);
  }

  function addItem() {
    setItems((prevItems) => {
      return [...prevItems, inputText];
    });
    setInputText("");
  }

  function deleteItem(event) {
    const listItem = event.target
    const listItemIndex = Array.from(listItem.parentNode.children).indexOf(listItem)
    setItems((prevState) => {
      return prevState.filter(function (item, index) {
        return index !== listItemIndex
      });
    });
    console.log("Item :", listItem);
    console.log("Index :", listItemIndex);
  }

  return (
    <div className="container">
      <div className="heading">
        <h1>To-Do List</h1>
      </div>
      <div className="form">
        <input onChange={handleChange} type="text" value={inputText} />
        <button onClick={addItem}>
          <span>Add</span>
        </button>
      </div>
      <div>
        <ul>
          {items.map((todoItem, index) => (
            <ToDoItem
              key={index}
              id={index}
              item={todoItem}
              deleteItem={deleteItem}
            />
          ))}
        </ul>
      </div>
    </div>
  );
}

ReactDOM.render(<App />, document.querySelector('#app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>

答案 2 :(得分:-1)

这就是我的处理方式,因为您的项目没有 id,只需传递索引就可以了

function deleteItem(index) {
    let aux = items;
    items.splice(index, 1);
    setItems([...aux]);
}

 <ToDoItem
    key={index}
    id={index}
    item={todoItem}
    deleteItem={deleteItem.bind(this, index)}
 />