【问题标题】:Deleting item from state array in react在反应中从状态数组中删除项目
【发布时间】:2025-12-25 02:35:06
【问题描述】:

我有一个如下所示的删除函数:

   this.deleteItem = item => event => {
      const { res, selectedItems } = this.state;
      res.splice(res.indexOf(item), 1);
      selectedItems.splice(res.indexOf(item), 1);

      this.setState({
        res
      });
    };

这里,res 是页面上显示的项目列表,selectedItems 是选择了哪些项目的列表。当 res 中的一个项目被删除时,selectedItems 应该被更新以从列表中删除该项目的索引。

但是,每当我尝试删除特定项目时,它只会删除添加到数组中的最后一个项目,而不是与单击的目标索引对应的项目。它的索引方式肯定有问题,但我一直无法确定来源。

我也尝试过引用here,但这不起作用,因为我需要将item 作为参数。

有什么好的方法可以解决这个问题?

非常感谢。

编辑:将函数更改为看起来像 @HMK 的响应。删除一个项目后,render 方法中console.log(res) 的输出是一个对象数组,其形式如下:

res 
(9) […]
​
0: Object { id: 0, name: "a", description: "description of a", … }
​
1: Object { id: 2, name: "b", description: "description of b", … }
​
2: Object { id: 3, name: "c", description: "description of c", … }
​
3: Object { id: 4, name: "d", description: "description of d", … }
​
4: Object { id: 5, name: "e", description: "description of e", … }
​
5: Object { id: 6, name: "f", description: "description of f", … }
​
6: Object { id: 7, name: "g", description: "description of g", … }
​
7: Object { id: 8, name: "h", description: "description of h", … }
​
8: Object { id: 9, name: "i", description: "description of i", … }
​
length: 9
​
<prototype>: Array []

deleteItem函数中console.log(JSON.stringify(item,undefined,2));的输出是从数组中删除的对象。

例如:

{
  "id": 10,
  "name": "j",
  "description": "description of j",
  "icon": "jIcon",
  "selected": false
}

当页面上的所有项目都被选中时,console.log("selecteditems:", JSON.stringify(selectedItems))的输出:

selecteditems: [0,1,2,3,4,5,6,7,8,9,10]

【问题讨论】:

  • 不要改变使用Array.prototype.filter 来创建一个删除项目的新数组。如果你这样做并且组件仍然呈现,那只意味着你没有优化任何东西(纯组件或 useMemo)

标签: javascript arrays reactjs indexing state


【解决方案1】:

要从数组中取出一个项目,您可以执行以下操作:

array.filter(item=>item!==itemToRemove)

所以在你的例子中:

this.deleteItem = item => event => {
  const filter = getter => val => getter(val) !== item.id
  this.setState({
    res: this.state.res.filter(filter(({id})=>id)),
    selectedItems: this.state.selectedItems.filter(
      filter(id=>id)
    )
  })
}

您遇到的问题是 res 存储了一个具有 id 的对象数组(例如:[{id:1}],然后 selectedItems 是一个存储 id 的数组:(例如:[1])。

Array.prototype.filter 的工作方式如下:newArray = array.filter(filterFunction)。对于数组 filterFunction 中的每个项目,都会使用该项目调用该项目。如果 filterFunction 返回 false,则该项目不会复制到 newArray,它返回 true,它会复制到 newArray。原始数组保持不变(因为它应该是状态,因为你不应该改变它)。

所以问题是您的过滤器函数获取数组的一个项目,决定它是否应该返回 true 或 false(true 表示保留该项目,false 表示不保留它)。因此,如果我过滤 res,过滤函数将收到 {id:X}(带有 id 的对象),但当我过滤 selectedItems 时,我将收到 Xid)。

但是,过滤器函数需要取出具有特定 id 的元素; res 是一个对象的属性,selectedItems 是一个 id。对于res,您可以编写一个getter 函数来从对象中获取id:resItem=&gt;resItem.id,给该函数一个来自res 的项目,它会返回一个id。对于selectedItems,getter 函数应该只返回它给出的值,因为selectedItems 中的项目 ids,所以getter 函数看起来像id=&gt;id

好的,让我们回到过滤器,我有一个名为 selectedItems [9] 的 id 数组,并且想要删除值为 9 的 id,我们称之为 idToRemove 以便我可以这样做:selectedItems.filter(id=&gt;id!==idToRemove)。同样的功能不适用于res,因为{id:9} 永远不会等于9

但是如果我将一个选择器传递给过滤器函数,这里会变得有点复杂,因为函数可以返回一个函数:

const idToRemove = 9;
//filter function return true for array item to stay in the copied array
// and false to not include the array item in the copy
const filter = getter => arrayItem =>
  getter(arrayItem) !== idToRemove;
//passing filter a getter function will return a function that takes
//  an item and uses the getter function on that item to compare it
//  to idToRemove
const compareId = filter(id => id);
console.log('keep 9?', compareId(9));
console.log('keep 8?', compareId(8));
//now create a filter function that takes an object and uses
//  the getter to get object.id and compares that to idToRemove
const compareObjectWithId = filter(object => object.id);
console.log('keep {id:9}?', compareObjectWithId({ id: 9 }));
console.log('keep {id:8}?', compareObjectWithId({ id: 8 }));

所以compareId 是我们可以用来从selectedItems 中过滤掉一个项目的函数,compareObjectWithId 是我们可以用来从res 中过滤掉一个项目的函数,下面是过滤器的使用方法:

const idToRemove = 9;
const createFilterFunction = getter => arrayItem =>
  getter(arrayItem) !== idToRemove;
console.log(
  '[2,9] remove id 9',
  [2, 9].filter(createFilterFunction(id => id))
);
console.log(
  '[{id:2},{id:9}] remove id 9',
  [{ id: 2 }, { id: 9 }].filter(
    createFilterFunction(object => object.id)
  )
);

为了完成,我将添加现代代码以从对象中删除键(不要在堆栈溢出代码 sn-p 上尝试此操作,因为它使用的是古老的 babel 版本)

const org = {a:1,b:2};
const withoutA = Object.fromEntries(
  Object.entries(org).filter(([key])=>key!=='a')//removed key 'a'
)

【讨论】:

  • 我明白你在说什么,虽然这不起作用 -- console.log(JSON.stringify(item,undefined,2) 打印出应该删除的正确项目(并且从 UI 视图中删除),但是长度调用此函数后,resselectedItems 的值不会改变。 .filter 是否应该从数组中删除该项目?这似乎不是这种情况,我仍然有同样的问题
  • 非常感谢您的澄清。我已经用 console.log 输出的结果更新了我的问题——尽管该项目已从 res 中删除,但它仍未从 selectedItems 中删除。你有什么建议?
  • 感谢您的建议 -- 我已经更新了我的代码,但从 res 删除的项目仍未从 selectedItems 删除。您认为为什么会出现这种情况,我该怎么做才能找出问题所在?
  • selectedItems 是页面上所有选定(选中)项目的列表。我编辑了我的答案以包括选择页面上所有项目时的console.log。当通过deleteItem 函数删除一个项目时,它会从res 数组中删除该项目,但 selectedItems 数组保持不变,我很难理解为什么.filter 被应用于两者。该项目需要从两个数组中删除
  • @HMF 再次感谢您的帮助和支持!