reactjs 使用挂接从数组中移除对象(useState)

v6ylcynt  于 2022-11-22  发布在  React
关注(0)|答案(8)|浏览(322)

我有一个对象数组。我需要添加一个函数来从我的数组中删除一个对象,而不使用“this”关键字。
我试着使用updateList(list.slice(list.indexOf(e.target.name, 1)))。这会删除数组中的所有内容,只保留最后一项,我不确定为什么。

const defaultList = [
{ name: "ItemOne" },
{ name: "ItemTwo" },
{ name: "ItemThree" }]

const [list, updateList] = useState(defaultList);

const handleRemoveItem = e => {
    updateList(list.slice(list.indexOf(e.target.name, 1)))
}

return (
    {list.map(item => {
        return ( 
            <>
            <span onClick={handleRemoveItem}>x </span>
            <span>{item.name}</span>
            </>
        )}
    }

)

预期:单击的项目将从列表中删除。
ACTUAL:整个列表被删除,减去数组中的最后一项。
提前感谢您的任何意见!

ruarlubt

ruarlubt1#

首先,带有click事件的span元素需要有一个name属性,否则,在e.target中将找不到name。也就是说,e.target.name是为表单元素(input、select等)保留的。因此,要真正使用name属性,您必须使用e.target.getAttribute("name")
另外,因为你有一个对象数组,所以使用list.indexOf(e.target.name)并不有效,因为当你迭代对象时,它会寻找一个string
最后,array.slice()返回一个新的数组**,该数组从您传递给它的索引**处的项开始。因此,如果您单击最后一项,您将只返回最后一项。
请尝试使用.filter()执行类似以下操作:codesandbox

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

const App = () => {
  const defaultList = [
    { name: "ItemOne" },
    { name: "ItemTwo" },
    { name: "ItemThree" }
  ];

  const [list, updateList] = useState(defaultList);

  const handleRemoveItem = (e) => {
   const name = e.target.getAttribute("name")
    updateList(list.filter(item => item.name !== name));
  };

  return (
    <div>
      {list.map(item => {
        return (
          <>
            <span name={item.name} onClick={handleRemoveItem}>
              x
            </span>
            <span>{item.name}</span>
          </>
        );
      })}
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
3pvhb19x

3pvhb19x2#

您可以使用Array.filter在一行程序中完成此操作:

const handleRemoveItem = name => {
    updateList(list.filter(item => item.name !== name))
}

Eta:您还需要在onClick处理程序中传递项目的名称:

{list.map(item => {
    return ( 
        <>
        <span onClick={() =>handleRemoveItem(item.name)}>x </span>
        <span>{item.name}</span>
        </>
    )}
bttbmeg0

bttbmeg03#

const defaultList = [
    { name: "ItemOne" },
    { name: "ItemTwo" },
    { name: "ItemThree" }
]

const [list, updateList] = useState(defaultList);

const handleRemoveItem = idx => {
    // assigning the list to temp variable
    const temp = [...list];

    // removing the element using splice
    temp.splice(idx, 1);

    // updating the list
    updateList(temp);
}

return (
    {list.map((item, idx) => (
      <div key={idx}>
        <button onClick={() => handleRemoveItem(idx)}>x </button>
        <span>{item.name}</span>
      </div>
    ))}

)
hjzp0vay

hjzp0vay4#

在我看来,到目前为止最好的答案有了小的改进

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

const App = () => {
  const defaultList = [
    { name: "ItemOne" },
    { name: "ItemTwo" },
    { name: "ItemThree" }
  ];

  const [list, updateList] = useState(defaultList);

  const handleRemoveItem = (item) => {
    updateList(list.filter(item => item.name !== name));
  };

  return (
    <div>
      {list.map(item => {
        return (
          <>
            <span onClick={()=>{handleRemoveItem(item)}}>
              x
            </span>
            <span>{item.name}</span>
          </>
        );
      })}
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

我们只是将其发送到句柄函数,而不是给出name属性

w46czmvw

w46czmvw5#

我想这个代码可以

let targetIndex = list.findIndex((each) => {each.name == e.target.name});
list.splice(targetIndex-1, 1);

我们需要检查对象内部的名称值,所以使用findIndex代替。然后将对象从目标索引开始剪切到目标索引后的1个数组。
Codepen
从你的评论来看,你的问题来自另一个部分。
更改此视图节

return ( 
        <>
        <span onClick={() => handleRemoveItem(item) }>x </span>
        <span>{item.name}</span>
        </>
    )}

更改函数handleRemoveItem格式

const handleRemoveItem = item => {
    list.splice(list.indexOf(item)-1, 1)
    updateList(list);
}
bwleehnv

bwleehnv6#

冗余的一个内衬-不推荐,因为难以测试/定型/扩展/重复/原因

<button onClick={() => setList(list.slice(item.id - 1))}

无导出的版本:

const handleDeleteItem = id => {
     const remainingItems = list.slice(id - 1)
     setList(remainingItems);
}

然而,我会考虑通过在另一个文件中使用帮助器函数来以不同的方式扩展逻辑结构。
考虑到这一点,我为filter和slice分别做了一个例子。我个人很喜欢这个用例中的slice选项,因为它使它更容易推理。显然,如果缩放,它在更大的列表上也稍微更有表现(参见参考资料)。
如果使用切片,请始终使用切片而不是拼接,除非您有充分的理由不这样做,因为它遵循功能样式(纯功能,没有副作用)

// use slice instead of splice (slice creates a shallow copy, i.e., 'mutates' )
export const excludeItemFromArray = (idx, array) => array.slice(idx-1)

// alternatively, you could use filter (also a shallow copy)
export const filterItemFromArray = (idx, array) => array.filter(item => item.idx !== idx)

示例(导入时同时使用过滤器选项与切片选项)

import {excludeItemFromArray, filterItemFromArray} from 'utils/arrayHelpers.js'

const exampleList = [
    { id: 1, name: "ItemOne" },
    { id: 2, name: "ItemTwo" },
    { id: 3, name: "ItemThree" }
]

const [list, setList] = useState(exampleList);

const handleDeleteItem = id => {
  
    //excluding the item (returning mutated list with excluded item)
    const remainingItems = excludeItemFromArray(id, list)

    //alternatively, filter item (returning mutated list with filtered out item)
    const remainingItems = filterItemFromArray(id, list)

    // updating the list state
    setList(remainingItems);
}

return (
    {list.map((item) => (
      <div key={item.id}>
        <button onClick={() => handleDeleteItem(item.id)}>x</button>
        <span>{item.name}</span>
      </div>
    ))}
)

参考文献:

oxf4rvwz

oxf4rvwz7#

使用此模式,数组不会跳转,但我们会获取以前的数据,创建新数据并返回。

const [list, updateList] = useState(
    { name: "ItemOne" },
    { name: "ItemTwo" },
    { name: "ItemThree" }
  ];);

     updateList((prev) => {
                return [
                    ...prev.filter((item, i) => item !== 'ItemTwo')
                ]
            })
6pp0gazn

6pp0gazn8#

这是因为slicesplice都会传回包含已移除元素的数组。
您需要对数组应用splice然后使用钩子提供的方法更新状态

const handleRemoveItem = e => {
    const newArr = [...list];
    newArr.splice(newArr.findIndex(item => item.name === e.target.name), 1)
    updateList(newArr)
}

相关问题