Ответ 1
Самый чистый способ сделать это, который я видел, - это filter
:
removeItem(index) {
this.setState({
data: this.state.data.filter((_, i) => i !== index)
});
}
Я пытаюсь найти лучший способ удалить элемент из массива в состоянии компонента. Так как я не должен изменять переменную 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. Это должно быть сделано при обращении к текущему состоянию при его обновлении.
Самый чистый способ сделать это, который я видел, - это filter
:
removeItem(index) {
this.setState({
data: this.state.data.filter((_, i) => i !== index)
});
}
Вы можете использовать update()
помощник по неизменяемости из react-addons-update
, который эффективно делает то же самое под капотом, но то, что вы делаете, хорошо.
this.setState(prevState => ({
data: update(prevState.data, {$splice: [[index, 1]]})
}))
Я считаю, что ссылаться на 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
;
Вот способ удаления элемента из массива в состоянии с использованием синтаксиса распространения ES6.
onRemovePerson: (index) => {
const data = this.state.data;
this.setState({
data: [...data.slice(0,index), ...data.slice(index+1)]
});
}
Я хочу присоединиться здесь, даже несмотря на то, что @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>
)}
Выше приведен отрывок из этого ответа из соответствующего поста.
Счастливого кодирования всем!
Как упомянуто в комментарии к ответу ephrion выше, filter() может быть медленным, особенно с большими массивами, так как он циклически ищет индекс, который, по-видимому, уже определен. Это чистое, но неэффективное решение.
В качестве альтернативы можно просто "нарезать" нужный элемент и объединить фрагменты.
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)
});
}
Вы можете сделать код более читабельным с помощью однострочной вспомогательной функции:
const removeElement = (arr, i) => [...arr.slice(0, i), ...arr.slice(i+1)];
тогда используйте это так:
this.setState(state => ({ places: removeElement(state.places, index) }));
Я использую это, надеюсь, что это не проблема и помощь.
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})
}
Вот простой способ сделать это:
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.
}
Надеюсь, что это поможет!!!