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ą?

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

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


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

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


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'].


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

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

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

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

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.