Bonne façon de pousser dans le tableau d'état

122

Je semble avoir des problèmes pour pousser les données dans un tableau d'état. J'essaye d'y parvenir de cette façon:

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

Mais je crois que c'est une manière incorrecte et provoque des problèmes de mutabilité?

Ilja
la source

Réponses:

145

Array push renvoie la longueur

this.state.myArray.push('new value')renvoie la longueur du tableau étendu, au lieu du tableau lui-même. Array.prototype.push () .

Je suppose que vous vous attendez à ce que la valeur retournée soit le tableau.

Immutabilité

Il semble que ce soit plutôt le comportement de React:

NE JAMAIS muter directement this.state, car l'appel de setState () par la suite peut remplacer la mutation que vous avez effectuée. Traitez cet état comme s'il était immuable. React.Component .

Je suppose que vous le feriez comme ceci (pas familier avec React):

var joined = this.state.myArray.concat('new value');
this.setState({ myArray: joined })
Márton Tamás
la source
1
Quand je le fais, console.log(this.state.myArray)c'est toujours un derrière. Une idée pourquoi?
Si8
@ Si8 Eh bien, je n'utilise pas trop React malheureusement. Mais la documentation dit: met en setState()file d'attente les modifications de l'état du composant et indique à React que ce composant et ses enfants doivent être rendus avec l'état mis à jour. Donc, je suppose que ce n'est tout simplement pas mis à jour à ce moment-là juste après l'avoir configuré. Pourriez-vous s'il vous plaît poster un exemple de code, où nous pouvons voir quel point vous définissez et enregistrez-le, s'il vous plaît?
Márton Tamás
Merci pour la réponse. Il est asynchrone donc il ne vous montrera pas les changements tout de suite. Cependant, setState a un rappel qui affiche la valeur correcte. Merci encore.
Si8
w3schools.com/jsref/jsref_concat_array.asp concat concatène deux tableaux (pas un tableau et une chaîne), .concat('new value'); devrait être .concat(['new value']);
Manohar Reddy Poreddy
1
@ManoharReddyPoreddy Les valeurs non-tableau sont parfaitement valides pour la concat()méthode. Voir: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... ( Tableaux et / ou valeurs à concaténer dans un nouveau tableau. )
Márton Tamás
176

En utilisant es6, cela peut être fait comme ceci:

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

Syntaxe de diffusion

Aliaksandr Sushkevich
la source
1
J'ai fait la même chose, il y a deux cas où myArray peut avoir des valeurs et ce n'est pas le cas. donc en cela, s'il a déjà des valeurs, cela fonctionne parfaitement bien. Mais dans aucune donnée..il ne met pas à jour l'état avec «nouvelle valeur». Une solution?
Krina Soni
Cela devrait fonctionner avec n'importe quel tableau, peu importe s'il a des valeurs ou non, il sera de toute façon déstructuré. Il y a peut-être quelque chose qui ne va pas ailleurs. Pourriez-vous s'il vous plaît montrer un exemple de votre code?
Aliaksandr Sushkevich
salut Veuillez vous référer à mon commentaire sous @Tamas answer. C'était juste un échantillon dans la console. J'ai essayé myArray: [... this.state.myArray, 'new value'] pour mettre à jour mon tableau d'état. Mais il ne concat que la dernière valeur. Pouvez-vous me dire la solution?
Johncy
@Johncy Je ne sais pas si votre problème est lié à cette question, essayez de poser une question distincte et de décrire le comportement attendu et je vais essayer de vous aider.
Aliaksandr Sushkevich
5
Selon la documentation React: "Parce que this.propset this.statepeut être mis à jour de manière asynchrone, vous ne devez pas vous fier à leurs valeurs pour calculer l'état suivant." Dans le cas de la modification d'un tableau, puisque le tableau existe déjà en tant que propriété de this.stateet que vous devez référencer sa valeur pour définir une nouvelle valeur, vous devez utiliser la forme de setState()qui accepte une fonction avec l'état précédent comme argument. Exemple: this.setState(prevState => ({ myArray: [...this.state.myArray, 'new value'] }));Voir: reactjs.org/docs/…
Bungle
104

Jamais recommandé de muter l'état directement.

L'approche recommandée dans les versions ultérieures de React consiste à utiliser une fonction de mise à jour lors de la modification des états pour éviter les conditions de concurrence:

Poussez la chaîne à la fin du tableau

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

Pousser la chaîne au début du tableau

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

Pousser l'objet à la fin du tableau

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

Pousser l'objet au début du tableau

this.setState(prevState => ({
  myArray: [ {"name": "object"}, ...prevState.myArray]
}))
Hemadri Dasari
la source
1
J'ai utilisé cette réponse. Cela fonctionne également pour le préfixe dans le tableau:this.setState((prevState) => ({ myArray: [values, ...prevState.myArray], }));
Gus
1
c'est une bien meilleure approche que la réponse acceptée et le fait comme le recommande la documentation React.
Ian J Miller
2
Définitivement +1 car les autres réponses ne suivent pas les dernières directives d'utilisation des rappels en cas de mutation de l'état avec lui-même.
Matt Fletcher
comment ajouter un autre objet de tableau dans un tableau d'état?
Chandni
14

Vous ne devriez pas du tout exploiter l'état. Du moins, pas directement. Si vous souhaitez mettre à jour votre tableau, vous voudrez faire quelque chose comme ça.

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

Il n'est pas souhaitable de travailler directement sur l'objet d'état. Vous pouvez également jeter un œil aux assistants d'immuabilité de React.

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

Christoph
la source
5
Je crois que cette réponse est la bonne, même si j'aurais aimé savoir pourquoi nous ne pouvons pas opérer sur l'état, c'est-à-dire pourquoi ce n'est pas souhaitable. Après un peu de recherche, j'ai trouvé le didacticiel React suivant - Pourquoi l'immutabilité est importante , qui a aidé à remplir les informations manquantes et le didacticiel utilise également .slice()pour créer un nouveau tableau et préserver l'immutabilité. Merci pour l'aide.
BebopSong
11

Vous pouvez utiliser la .concatméthode pour créer une copie de votre tableau avec de nouvelles données:

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

Mais méfiez-vous du comportement spécial de la .concatméthode lors du passage de tableaux - [1, 2].concat(['foo', 3], 'bar')cela entraînera [1, 2, 'foo', 3, 'bar'].

Ginden
la source
1

Ce code fonctionne pour moi:

fetch('http://localhost:8080')
  .then(response => response.json())
  .then(json => {
  this.setState({mystate: this.state.mystate.push.apply(this.state.mystate, json)})
})
Hamid Hosseinpour
la source
3
Bienvenue dans Stack Overflow! Veuillez ne pas répondre uniquement avec le code source. Essayez de fournir une belle description du fonctionnement de votre solution. Voir: Comment rédiger une bonne réponse? . Merci
sɐunıɔ ןɐ qɐp
J'ai essayé cela mais en vain. Voici mon codefetch(`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
et j'ai d'abord initialisé l'état comme un tableau vide, c'est-à-dire this.state = { reports=[] }... pls j'aimerai savoir ce que je fais de mal
henrie
@Hamid Hosseinpour
henrie
1

React-Native

si vous voulez également que votre interface utilisateur (c.-à-d. ur flatList) soit à jour, utilisez PrevState: dans l'exemple ci-dessous, si l'utilisateur clique sur le bouton, il va ajouter un nouvel objet à la liste (à la fois dans le modèle et dans l'interface utilisateur )

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

De la manière suivante, nous pouvons vérifier et mettre à jour les objets

this.setState(prevState => ({
    Chart: this.state.Chart.length !== 0 ? [...prevState.Chart,data[data.length - 1]] : data
}));
KARTHIKEYAN.A
la source
0

Ici, vous ne pouvez pas pousser l'objet vers un tableau d'état comme celui-ci. Vous pouvez pousser comme votre chemin dans un tableau normal. Ici, vous devez définir l'état,

this.setState({ 
     myArray: [...this.state.myArray, 'new value'] 
})
Sachin Muthumala
la source
-1

Si vous essayez juste de mettre à jour l'état comme ça

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

Considérez cette approche

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

Fondamentalement, prevState écrit this.state pour nous.

monsieur personne
la source