在组件状态下从数组中删除元素

IT技术 javascript reactjs
2021-02-22 04:07:49

我试图找到从处于组件状态的数组中删除元素的最佳方法。由于我不应该this.state直接修改变量,是否有比我这里更好的方法(更简洁)从数组中删除元素?:

  onRemovePerson: function(index) {
    this.setState(prevState => { // pass callback in setState to avoid race condition
      let newData = prevState.data.slice() //copy array from prevState
      newData.splice(index, 1) // remove element
      return {data: newData} // update state
    })
  },

谢谢你。

更新

这已更新为使用 setState 中的回调。这应该在更新它时引用当前状态时完成。

6个回答

我见过的最干净的方法是filter

removeItem(index) {
  this.setState({
    data: this.state.data.filter((_, i) => i !== index)
  });
}
惊人。我一直在使用 .filter ,但从未考虑过在这种情况下使用它。:D
2021-04-20 04:07:49
@HussienK_有时用于表示未使用的参数。在这里,它是数组中的当前项。
2021-04-24 04:07:49
这是干净的代码,但是,对于大型数组,这种方法很慢。原因是,它遍历整个数组以找到一个看起来已经确定的索引。
2021-04-25 04:07:49
@MattEllis 由于 React 的状态更新无论如何都是不可变的,因此无论如何您都将在列表大小上产生 O(n) 来复制它。如果这是一个重大的性能损失,我会感到惊讶。
2021-05-02 04:07:49
不建议this.state评估为 的输入this.setState(),即使是一成不变的。请参阅我上面的回答以参考有关此主题的官方 React 文档。
2021-05-04 04:07:49

您可以使用update()来自react-addons-update不变性助手,它实际上幕后做同样的事情,但您所做的很好。

this.setState(prevState => ({
  data: update(prevState.data, {$splice: [[index, 1]]})
}))
比你链接到的那个简单得多的例子:)
2021-05-02 04:07:49
react-addons-update现在已弃用(2016 年)。immutability-helper可作为替代品。github.com/kolodny/immutability-helper 另外,请参阅下面关于不在 this.setState() 中直接改变 this.state 的回答。
2021-05-14 04:07:49

我相信不鼓励this.state在里面引用setState()状态更新可能是异步的)。

文档建议使用setState()回调函数,以便在更新发生时在运行时传入 prevState。所以这就是它的样子:

在没有 ES6 的情况下使用 Array.prototype.filter

removeItem : function(index) {
  this.setState(function(prevState){
    return { data : prevState.data.filter(function(val, i) {
      return i !== index;
    })};
  });
}

使用 Array.prototype.filter 和 ES6 箭头函数

removeItem(index) {
  this.setState((prevState) => ({
    data: prevState.data.filter((_, i) => i !== index)
  }));
}

使用不变性助手

import update from 'immutability-helper'
...
removeItem(index) {
  this.setState((prevState) => ({
    data: update(prevState.data, {$splice: [[index, 1]]})
  }))
}

使用点差

function removeItem(index) {
  this.setState((prevState) => ({
    data: [...prevState.data.slice(0,index), ...prevState.data.slice(index+1)]
  }))
}

请注意,在每个实例中,无论使用何种技术,this.setState()都会传递一个回调,而不是旧的对象引用this.state

这是最好的解决方案,虽然不是最简单的
2021-04-27 04:07:49
添加了各种技术的使用 prevState 回调的示例。
2021-04-30 04:07:49
如果我这样做怎么办? this.setState({ data: [...this.state.data.slice(0, index), ...this.state.data.slice(index + 1)] }); 使用@user1628461 显示this.stateprevState回调选项代替回调选项是否错误
2021-04-30 04:07:49
谢谢,使用传播也可以更新中间的元素而不是删除它,这就是我需要的。
2021-05-08 04:07:49
这是正确答案,另请参阅不改变数据的力量
2021-05-14 04:07:49

这是一种使用 ES6 扩展语法从状态数组中删除元素的方法。

onRemovePerson: (index) => {
  const data = this.state.data;
  this.setState({ 
    data: [...data.slice(0,index), ...data.slice(index+1)]
  });
}
谢谢!感觉这是最自然的方法。
2021-04-27 04:07:49

即使@pscl已经正确回答了这个问题,我也想在这里插一句,以防其他人遇到我遇到的同样问题。在这 4 种方法中,我选择使用带有箭头函数的 es6 语法,因为它简洁且不依赖于外部库:

使用 Array.prototype.filter 和 ES6 箭头函数

removeItem(index) {
  this.setState((prevState) => ({
    data: prevState.data.filter((_, i) => i != index)
  }));
}

正如你所看到的,我做了一个轻微的修改来忽略索引的类型(!==to !=),因为在我的例子中我是从字符串字段中检索索引。

如果您在客户端删除元素时看到奇怪的行为,另一个有用的观点是永远不要使用数组的索引作为元素的键

// bad
{content.map((content, index) =>
  <p key={index}>{content.Content}</p>
)}

当 React 与虚拟 DOM 发生变化时,它会查看键来确定发生了什么变化。因此,如果您使用索引并且数组中少了一个,它将删除最后一个。相反,像这样使用内容的 id 作为键。

// good
{content.map(content =>
  <p key={content.id}>{content.Content}</p>
)}

以上是来自相关帖子的这个答案的摘录

祝大家编码愉快!