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

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

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


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

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


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


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

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

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

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

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.