首页 > 解决方案 > 在反应中从状态数组中删除项目

问题描述

我有一个如下所示的删除功能:

   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的列表,是选择了哪些项目的列表。删除项目时resselectedItems应更新以从列表中删除该项目的索引。

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

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

什么是解决这个问题的好方法?

非常感谢。

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

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 []

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

例如:

{
  "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]

标签: javascriptarraysreactjsindexingstate

解决方案


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

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。原始数组保持不变(因为它应该是状态,因为你不应该改变它)。

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

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

好的,让我们回到过滤器,我有一个名为selectedItems[9] 的 id 数组,并且想要删除值为 9 的 id,让我们称之为 idToRemove 以便我可以这样做:selectedItems.filter(id=>id!==idToRemove)。相同的功能将无法使用,res因为{id:9}never equals 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可以用来从中过滤出一个项目的函数也是一个函数,我们可以用来从中过滤出一个项目selectedItemscompareObjectWithId函数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)
  )
);

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

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

推荐阅读