Я пытаюсь найти лучший способ удалить элемент из массива в состоянии компонента. Так как я не должен изменять переменную 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]]})
}))
react-addons-update
теперь устарела (2016). immutability-helper
доступен в качестве замены. github.com/kolodny/immutability-helper Также, пожалуйста, смотрите мой ответ ниже о том, чтобы не изменять му. this.state непосредственно внутри this.setState ().
Я считаю, что привязка this.state
внутри setState()
обескуражена
https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
Документы рекомендуют использовать 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 Arrow
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()
передается обратный вызов, а не ссылка на объект old 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>
)}
Выше приведен отрывок из этого ответа из соответствующего поста.
Счастливого кодирования всем!
Вы можете использовать эту функцию, если хотите удалить элемент (без индекса)
removeItem(item) {
this.setState(prevState => {
data: prevState.data.filter(i => i !== item)
});
}
Как упомянуто в комментарии к ответу ephrion выше, filter() может быть медленным, особенно с большими массивами, так как он циклически ищет индекс, который, по-видимому, уже определен. Это чистое, но неэффективное решение.
В качестве альтернативы можно просто "нарезать" нужный элемент и объединить фрагменты.
var dummyArray = [];
this.setState({data: dummyArray.concat(this.state.data.slice(0, index), this.state.data.slice(index))})
Надеюсь это поможет!
Вы можете сделать код более читабельным с помощью однострочной вспомогательной функции:
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
this.state.yourArray.splice(index, 1)
this.setState({yourArray: this.state.yourArray})
}
this.state
напрямую. Вы должны сделать копию this.state.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.
}
Надеюсь, что это поможет!!!