Удаление элемента из массива в состоянии компонента

Я пытаюсь найти лучший способ удалить элемент из массива в состоянии компонента. Так как я не должен изменять переменную 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. Это должно быть сделано при обращении к текущему состоянию при его обновлении.

Ответ 1

Самый чистый способ сделать это, который я видел, - это filter:

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

Ответ 3

Я считаю, что ссылаться на this.state внутри setState() не рекомендуется (обновления состояния могут быть асинхронными).

Документы рекомендуют использовать setState() с функцией обратного вызова, чтобы prevState передавался во время выполнения, когда происходит обновление. Вот как это будет выглядеть:

Использование Array.prototype.filter без ES6

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

Использование Spread

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

Обратите внимание, что в каждом случае, независимо от используемой техники, this.setState() передается обратный вызов, а не ссылка на объект на старый this.state;

Ответ 4

Вот способ удаления элемента из массива в состоянии с использованием синтаксиса распространения ES6.

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

Ответ 5

Я хочу присоединиться здесь, даже несмотря на то, что @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 при изменении, он просматривает ключи, чтобы определить, что изменилось. Поэтому, если вы используете индексы, а в массиве их на единицу меньше, последний удалит последний. Вместо этого используйте идентификатор содержимого в качестве ключей, как это.

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

Выше приведен отрывок из этого ответа из соответствующего поста.

Счастливого кодирования всем!

Ответ 6

Как упомянуто в комментарии к ответу ephrion выше, filter() может быть медленным, особенно с большими массивами, так как он циклически ищет индекс, который, по-видимому, уже определен. Это чистое, но неэффективное решение.

В качестве альтернативы можно просто "нарезать" нужный элемент и объединить фрагменты.

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

Надеюсь это поможет!

Ответ 7

Вы можете использовать эту функцию, если хотите удалить элемент (без индекса)

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

Ответ 8

Вы можете сделать код более читабельным с помощью однострочной вспомогательной функции:

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

тогда используйте это так:

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

Ответ 9

Я использую это, надеюсь, что это не проблема и помощь.

removeItem(item){
    const index = this.state.yourArray.indexOf(item);
    if (index < 0) return
    let yourArray = [...this.state.yourArray]
    yourArray.splice(index, 1)
    this.setState({yourArray: this.state.yourArray})
}

Ответ 10

Вот простой способ сделать это:

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.
}

Надеюсь, что это поможет!!!