Próbuję znaleźć najlepszy sposób na usunięcie elementu z tablicy w stanie komponentu. Ponieważ nie powinienem this.state
bezpośrednio modyfikować zmiennej, czy istnieje lepszy sposób (bardziej zwięzły) na usunięcie elementu z tablicy niż to, co mam tutaj ?:
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
})
},
Dziękuję Ci.
zaktualizowany
Zostało to zaktualizowane, aby używać wywołania zwrotnego w setState. Należy to zrobić podczas odwoływania się do bieżącego stanu podczas jego aktualizacji.
javascript
reactjs
aherriot
źródło
źródło
Odpowiedzi:
Najczystszym sposobem na zrobienie tego, jaki widziałem, jest
filter
:removeItem(index) { this.setState({ data: this.state.data.filter((_, i) => i !== index) }); }
źródło
_
jest czasami używany do reprezentowania nieużywanego argumentu. Tutaj jest to bieżący element w tablicy.this.state
jako dane wejściowethis.setState()
, nawet niezmienne, nie jest zalecane. zobacz moją odpowiedź powyżej, aby zapoznać się z oficjalnymi dokumentami Reacta na ten temat.Możesz użyć
update()
pomocnika niezmiennościreact-addons-update
, który skutecznie robi to samo pod maską, ale to, co robisz, jest w porządku.this.setState(prevState => ({ data: update(prevState.data, {$splice: [[index, 1]]}) }))
źródło
react-addons-update
jest teraz przestarzała (2016).immutability-helper
jest dostępny jako zamiennik. github.com/kolodny/immutability-helper Proszę również zapoznać się z moją odpowiedzią poniżej dotyczącą nie mutowania this.state bezpośrednio w this.setState ().Uważam, że odwoływanie się do
this.state
wewnątrz programu niesetState()
jest zalecane ( aktualizacje stanu mogą być asynchroniczne ).Dokumentacja zaleca używanie
setState()
z funkcją wywołania zwrotnego, aby prevState był przekazywany w czasie wykonywania, gdy nastąpi aktualizacja. A więc tak by to wyglądało:Używanie Array.prototype.filter bez ES6
removeItem : function(index) { this.setState(function(prevState){ return { data : prevState.data.filter(function(val, i) { return i !== index; })}; }); }
Używanie Array.prototype.filter z funkcjami strzałek ES6
removeItem(index) { this.setState((prevState) => ({ data: prevState.data.filter((_, i) => i !== index) })); }
Korzystanie z pomocnika niezmienności
import update from 'immutability-helper' ... removeItem(index) { this.setState((prevState) => ({ data: update(prevState.data, {$splice: [[index, 1]]}) })) }
Korzystanie z rozpowszechniania
function removeItem(index) { this.setState((prevState) => ({ data: [...prevState.data.slice(0,index), ...prevState.data.slice(index+1)] })) }
Zauważ, że w każdym przypadku, niezależnie od użytej techniki,
this.setState()
przekazywane jest wywołanie zwrotne, a nie odwołanie do obiektuthis.state
;źródło
this.setState({ data: [...this.state.data.slice(0, index), ...this.state.data.slice(index + 1)] });
czy używaniethis.state
zamiastprevState
opcji callback pokazanej przez @ user1628461 jest niewłaściwe?Oto sposób na usunięcie elementu z tablicy w stanie przy użyciu składni rozsyłania ES6.
onRemovePerson: (index) => { const data = this.state.data; this.setState({ data: [...data.slice(0,index), ...data.slice(index+1)] }); }
źródło
Chcę tu zadzwonić, mimo że @pscl odpowiedział już poprawnie na to pytanie, na wypadek gdyby ktoś inny napotkał ten sam problem, co ja. Z podanych 4 metod wybrałem użycie składni es6 z funkcjami strzałkowymi ze względu na jej zwięzłość i brak zależności od zewnętrznych bibliotek:
Używanie Array.prototype.filter z funkcjami strzałek ES6
removeItem(index) { this.setState((prevState) => ({ data: prevState.data.filter((_, i) => i != index) })); }
Jak widać, dokonałem niewielkiej modyfikacji, aby zignorować typ indeksu (
!==
to!=
), ponieważ w moim przypadku pobierałem indeks z pola tekstowego.Innym pomocnym punktem, jeśli widzisz dziwne zachowanie podczas usuwania elementu po stronie klienta, jest NIGDY nie używaj indeksu tablicy jako klucza dla elementu :
// bad {content.map((content, index) => <p key={index}>{content.Content}</p> )}
Kiedy React porównuje się z wirtualnym DOM po zmianie, będzie patrzył na klawisze, aby określić, co się zmieniło. Więc jeśli używasz indeksów, a w tablicy jest o jeden mniej, usunie to ostatni. Zamiast tego użyj identyfikatorów treści jako kluczy, w ten sposób.
// good {content.map(content => <p key={content.id}>{content.Content}</p> )}
Powyższe jest fragmentem tej odpowiedzi z pokrewnego postu .
Szczęśliwego kodowania wszystkim!
źródło
Możesz użyć tej funkcji, jeśli chcesz usunąć element (bez indeksu)
removeItem(item) { this.setState(prevState => { data: prevState.data.filter(i => i !== item) }); }
źródło
Jak wspomniano w komentarzu do powyższej odpowiedzi ephriona, filter () może działać wolno, szczególnie w przypadku dużych tablic, ponieważ wykonuje pętlę w celu wyszukania indeksu, który wydaje się być już określony. To czyste, ale nieefektywne rozwiązanie.
Alternatywnie można po prostu „wyciąć” żądany element i połączyć fragmenty.
var dummyArray = []; this.setState({data: dummyArray.concat(this.state.data.slice(0, index), this.state.data.slice(index))})
Mam nadzieję że to pomoże!
źródło
Możesz uczynić kod bardziej czytelnym za pomocą jednowierszowej funkcji pomocniczej:
const removeElement = (arr, i) => [...arr.slice(0, i), ...arr.slice(i+1)];
następnie użyj go w ten sposób:
this.setState(state => ({ places: removeElement(state.places, index) }));
źródło
Tylko sugestia, w swoim kodzie zamiast używać
let newData = prevState.data
możesz użyć spreadu, który jest wprowadzony w ES6, czyli możesz użyćlet newData = ...prevState.data
do kopiowania tablicyTrzy kropki ... reprezentują operatory rozprzestrzeniania lub parametry odpoczynku ,
Umożliwia rozwinięcie wyrażenia tablicowego lub ciągu znaków lub czegokolwiek, co może być iterowane, w miejscach, w których oczekiwanych jest zero lub więcej argumentów dla wywołań funkcji lub elementów tablicy.
Dodatkowo możesz usunąć element z tablicy za pomocą następujących
onRemovePerson: function(index) { this.setState((prevState) => ({ data: [...prevState.data.slice(0,index), ...prevState.data.slice(index+1)] })) }
Mam nadzieję, że to się przyczyni!
źródło
Oto prosty sposób na zrobienie tego:
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. }
Mam nadzieję, że to pomoże!!!
źródło
delete
dzieje się tak dlatego, że usuwa element, ale indeksy nie są aktualizowane, a zatem nie byłoby to dobre podejście do zwykłych potrzeb.