从组件状态的数组中删除元素

Removing element from array in component state

我正在尝试找到从组件状态的数组中删除元素的最佳方法。由于我不应该直接修改 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 中的回调。在更新当前状态时引用当前状态时应该这样做。

您可以使用 update() immutability helper from react-addons-update,它在后台有效地执行相同的操作,但您所做的很好。

this.setState(prevState => ({
  data: update(prevState.data, {$splice: [[index, 1]]})
}))

我见过的最简洁的方法是 filter:

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

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

onRemovePerson: (index) => {
  const data = this.state.data;
  this.setState({ 
    data: [...data.slice(0,index), ...data.slice(index+1)]
  });
}

这里有一个简单的方法:

removeFunction(key){
  const data = {...this.state.data}; //Duplicate state.
  delete data[key];                  //remove Item form stateCopy.
  this.setState({data});             //Set state as the modify one.
}

希望对您有所帮助!!!

我认为不鼓励在 setState() 中引用 this.state (State Updates May Be Asynchronous)。

文档建议使用 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)
  }));
}

使用immutability-helper

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 的对象引用;

正如上面对 ephrion 的回答的评论中提到的,filter() 可能会很慢,尤其是对于大型数组,因为它会循环查找似乎已经确定的索引。这是一个干净但效率低下的解决方案。

作为一种替代方法,可以简单地 'slice' 出所需的元素并连接片段。

var dummyArray = [];    
this.setState({data: dummyArray.concat(this.state.data.slice(0, index), this.state.data.slice(index))})

希望对您有所帮助!

如果你想删除元素(没有索引),你可以使用这个函数

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

尽管这个问题已经 我想在这里补充一下,以防其他人遇到我遇到的同样问题。在 4 种方法中,我选择使用带箭头函数的 es6 语法,因为它简洁且不依赖外部库:

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

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

如您所见,我略作修改以忽略索引类型(!==!=),因为在我的例子中,我是从字符串字段中检索索引。

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

// 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>
)}

以上摘自this answer from a related post.

祝大家编程愉快!

您可以使用一行辅助函数使代码更具可读性:

const removeElement = (arr, i) => [...arr.slice(0, i), ...arr.slice(i+1)];

然后像这样使用它:

this.setState(state => ({ places: removeElement(state.places, index) }));

只是一个建议,在你的代码中你可以使用 ES6 中引入的 spread 而不是使用 let newData = prevState.data,你可以使用 let newData = ...prevState.data 来复制数组

三个点...代表Spread Operators or Rest Parameters,

它允许在需要零个或多个函数调用参数或数组元素的地方扩展数组表达式或字符串或任何可以迭代的内容。

此外,您可以使用以下方法从数组中删除项目

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

希望这有帮助!!