Prawidłowy sposób wypychania do tablicy stanów

122

Wydaje się, że mam problemy z przesyłaniem danych do tablicy stanów. Staram się to osiągnąć w ten sposób:

this.setState({ myArray: this.state.myArray.push('new value') })

Ale uważam, że to niewłaściwy sposób i powoduje problemy ze zmiennością?

Ilja
źródło

Odpowiedzi:

146

Wypchnięcie tablicy zwraca długość

this.state.myArray.push('new value')zwraca długość rozszerzonej tablicy zamiast samej tablicy. Array.prototype.push () .

Myślę, że oczekujesz, że zwrócona wartość będzie tablicą.

Niezmienność

Wygląda na to, że jest to raczej zachowanie Reacta:

NIGDY nie modyfikuj this.state bezpośrednio, ponieważ późniejsze wywołanie setState () może zastąpić dokonaną przez Ciebie mutację. Traktuj this.state tak, jakby był niezmienny. React.Component .

Myślę, że zrobiłbyś to w ten sposób (nie znasz Reacta):

var joined = this.state.myArray.concat('new value');
this.setState({ myArray: joined })
Márton Tamás
źródło
1
Kiedy to robię console.log(this.state.myArray), zawsze jest jeden z tyłu. Każdy pomysł, dlaczego?
Si8
@ Si8 Cóż, niestety nie używam zbyt często React. Ale dokumentacja mówi: setState()kolejkuje zmiany do stanu komponentu i mówi Reactowi, że ten komponent i jego dzieci muszą zostać ponownie wyrenderowane ze zaktualizowanym stanem. Więc myślę, że nie jest aktualizowany w tym momencie zaraz po ustawieniu. Czy mógłbyś zamieścić przykładowy kod, w którym możemy zobaczyć, który punkt go ustawiasz i logujesz?
Márton Tamás
Dzięki za odpowiedzi. Jest asynchroniczny, więc nie pokaże od razu zmian. Jednak setState ma wywołanie zwrotne, które wyświetlało poprawną wartość. Dzięki jeszcze raz.
Si8
w3schools.com/jsref/jsref_concat_array.asp concat łączy dwie tablice (nie tablicę i ciąg), .concat('new value'); powinno być .concat(['new value']);
Manohar Reddy Poreddy
1
@ManoharReddyPoreddy Wartości niebędące tablicami są całkowicie prawidłowe dla concat()metody. Zobacz: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ( Tablice i / lub wartości do połączenia w nową tablicę. )
Márton Tamás
176

Używając es6 można to zrobić w następujący sposób:

this.setState({ myArray: [...this.state.myArray, 'new value'] }) //simple value
this.setState({ myArray: [...this.state.myArray, ...[1,2,3] ] }) //another array

Składnia spreadów

Aliaksandr Sushkevich
źródło
1
Zrobiłem to samo, są dwa przypadki, w których myArray może mieć wartości i nie będzie. więc jeśli ma już wartości, działa doskonale. Ale w żadnych danych… nie aktualizuje stanu o „nową wartość”. Jakieś rozwiązanie?
Krina Soni
Powinien działać z dowolnymi tablicami, nie ma znaczenia, czy ma wartości, czy nie, i tak zostanie zniszczony. Może coś jest nie tak w innym miejscu. Czy mógłbyś pokazać przykład swojego kodu?
Aliaksandr Sushkevich
cześć Proszę odnieść mój komentarz pod odpowiedzią @Tamas. To była tylko próbka w konsoli. Próbowałem myArray: [... this.state.myArray, 'nowa wartość'], aby zaktualizować moją tablicę stanów.Ale zawiera ona tylko ostatnią wartość. Czy mógłbyś mi powiedzieć rozwiązanie?
Johncy
@Johncy Nie jestem pewien, czy Twój problem jest związany z tym pytaniem, spróbuj zadać osobne pytanie i opisać oczekiwane zachowanie, a postaram się Ci pomóc.
Aliaksandr Sushkevich
5
Zgodnie z dokumentacją React: „Ponieważ this.propsi this.statemogą być aktualizowane asynchronicznie, nie należy polegać na ich wartościach przy obliczaniu następnego stanu”. W przypadku modyfikowania tablicy, ponieważ tablica już istnieje jako właściwość this.statei trzeba odwołać się do jej wartości, aby ustawić nową wartość, należy użyć postaci, setState()która akceptuje funkcję z poprzednim stanem jako argument. Przykład: this.setState(prevState => ({ myArray: [...this.state.myArray, 'new value'] }));Zobacz: awarejs.org/docs/…
Bungle
104

Nigdy nie zaleca się bezpośredniej mutacji stanu.

Zalecanym podejściem w późniejszych wersjach Reacta jest użycie funkcji aktualizatora podczas modyfikowania stanów, aby zapobiec sytuacjom wyścigu:

Wypchnij ciąg na koniec tablicy

this.setState(prevState => ({
  myArray: [...prevState.myArray, "new value"]
}))

Wypchnij ciąg na początek tablicy

this.setState(prevState => ({
  myArray: ["new value", ...prevState.myArray]
}))

Wypchnij obiekt na koniec tablicy

this.setState(prevState => ({
  myArray: [...prevState.myArray, {"name": "object"}]
}))

Wypchnij obiekt na początek tablicy

this.setState(prevState => ({
  myArray: [ {"name": "object"}, ...prevState.myArray]
}))
Hemadri Dasari
źródło
1
Użyłem tej odpowiedzi. Działa również przy wstawianiu do tablicy:this.setState((prevState) => ({ myArray: [values, ...prevState.myArray], }));
Gus
1
jest to znacznie lepsze podejście niż akceptowana odpowiedź i robi to tak, jak zaleca dokumentacja React.
Ian J Miller
2
Zdecydowanie daje +1, ponieważ inne odpowiedzi nie są zgodne z najnowszymi wytycznymi dotyczącymi używania wywołań zwrotnych w przypadku mutowania stanu ze sobą.
Matt Fletcher,
jak dodać kolejne obiekty tablicy w tablicy stanów?
Chandni
14

W ogóle nie powinieneś operować stanem. Przynajmniej nie bezpośrednio. Jeśli chcesz zaktualizować swoją tablicę, będziesz chciał zrobić coś takiego.

var newStateArray = this.state.myArray.slice();
newStateArray.push('new value');
this.setState(myArray: newStateArray);

Bezpośrednia praca na obiekcie stanu nie jest pożądana. Możesz również przyjrzeć się pomocnikom niezmienności Reacta.

https://facebook.github.io/react/docs/update.html

Christoph
źródło
5
Uważam, że ta odpowiedź jest poprawna, chociaż chciałbym wiedzieć, dlaczego nie możemy operować stanem, czyli dlaczego nie jest pożądane. Po krótkich poszukiwaniach znalazłem następujący samouczek dotyczący Reagowania - Dlaczego niezmienność jest ważna , który pomógł wypełnić brakujące informacje, a samouczek używa również .slice()do tworzenia nowej tablicy i zachowania niezmienności. Dzięki za pomoc.
BebopSong
11

Możesz użyć .concatmetody, aby utworzyć kopię swojej tablicy z nowymi danymi:

this.setState({ myArray: this.state.myArray.concat('new value') })

Ale uważaj na specjalne zachowanie .concatmetody podczas przekazywania tablic - [1, 2].concat(['foo', 3], 'bar')spowoduje to [1, 2, 'foo', 3, 'bar'].

Ginden
źródło
1

Ten kod działa dla mnie:

fetch('http://localhost:8080')
  .then(response => response.json())
  .then(json => {
  this.setState({mystate: this.state.mystate.push.apply(this.state.mystate, json)})
})
Hamid Hosseinpour
źródło
3
Witamy w Stack Overflow! Nie odpowiadaj tylko za pomocą kodu źródłowego. Postaraj się przedstawić miły opis tego, jak działa Twoje rozwiązanie. Zobacz: Jak napisać dobrą odpowiedź? . Dzięki
sɐunıɔ ןɐ qɐp
Próbowałem tego, ale bezskutecznie. Oto mój kodfetch(`api.openweathermap.org/data/2.5/forecast?q=${this.searchBox.value + KEY} `) .then( response => response.json() ) .then( data => { this.setState({ reports: this.state.reports.push.apply(this.state.reports, data.list)}); });
henrie
i po raz pierwszy zainicjowałem stan jako pustą tablicę, tj this.state = { reports=[] }... pls chciałbym wiedzieć, co robię źle
henrie
@Hamid Hosseinpour
henrie
1

React-Native

jeśli chcesz również, aby Twój UI (np. ur flatList) był aktualny, użyj PrevState: w poniższym przykładzie, jeśli użytkownik kliknie przycisk, doda nowy obiekt do listy (zarówno w modelu, jak iw UI )

data: ['shopping','reading'] // declared in constructor
onPress={() => {this.setState((prevState, props) => {
return {data: [new obj].concat(prevState.data) };
})}}. 
Mahgol Fa
źródło
0

W następujący sposób możemy sprawdzić i zaktualizować obiekty

this.setState(prevState => ({
    Chart: this.state.Chart.length !== 0 ? [...prevState.Chart,data[data.length - 1]] : data
}));
KARTHIKEYAN.A
źródło
0

Tutaj nie możesz wypchnąć obiektu do tablicy stanów, takiej jak ta. Możesz pchać tak jak w normalnej tablicy. Tutaj musisz ustawić stan,

this.setState({ 
     myArray: [...this.state.myArray, 'new value'] 
})
Sachin Muthumala
źródło
-1

Jeśli próbujesz tylko zaktualizować stan w ten sposób

   handleClick() {
        this.setState(
{myprop: this.state.myprop +1}
        })
    }

Rozważ to podejście

   handleClick() {
        this.setState(prevState => {
            return {
                count: prevState.count + 1
            }
        })
    }

Zasadniczo prevState pisze dla nas this.state.

pan nikt
źródło