Modification correcte des tableaux d'état dans ReactJS
Je veux ajouter un élément à la fin d'un state
tableau, est-ce la bonne façon de le faire?
this.state.arrayvar.push(newelement);
this.setState({arrayvar:this.state.arrayvar});
Je crains que la modification du tableau en place avec push
puisse causer des problèmes - est-ce sûr?
L'alternative de faire une copie du tableau, et setState
cela semble inutile.
6 réponses
Les documents React indiquent:
Traite ça.Etat comme si elle était immuable.
Votre {[3] } va muter l'état directement et cela pourrait potentiellement conduire à un code sujet aux erreurs, même si vous "réinitialisez" l'état par la suite. F. ex, cela pourrait conduire à ce que certaines méthodes de cycle de vie comme componentDidUpdate
ne se déclenchent pas.
L'approche recommandée dans les versions ultérieures de React consiste à utiliser une fonction updater lors de la modification d'États pour empêcher la course conditions:
this.setState(prevState => ({
arrayvar: [...prevState.arrayvar, newelement]
}))
Le "gaspillage" de mémoire n'est pas un problème comparé aux erreurs que vous pourriez rencontrer en utilisant des modifications d'état non standard.
Syntaxe Alternative pour les versions précédentes de React
Vous pouvez utiliser concat
pour obtenir une syntaxe propre car elle renvoie un nouveau tableau:
this.setState({
arrayvar: this.state.arrayvar.concat([newelement])
})
Dans ES6, vous pouvez utiliser l'opérateur Spread :
this.setState({
arrayvar: [...this.state.arrayvar, newelement]
})
Plus facile, si vous utilisez ES6
.
initialArray = [1, 2, 3];
newArray = [ ...initialArray, 4 ]; // --> [1,2,3,4]
Nouveau tableau sera [1,2,3,4]
Pour mettre à jour votre état dans React
this.setState({arrayvar:[...this.state.arrayvar, newelement]});
Le moyen le plus simple avec ES6
:
this.setState(prevState => ({
array: [...prevState.array, newElement]
}))
React peut mettre à jour par lots, et donc l'approche correcte est de fournir à setState une fonction qui effectue la mise à jour.
Pour L'addon react update, ce qui suit fonctionnera de manière fiable:
this.setState( (state) => update(state, {array: {$push: [4]}}) );
Ou pour concat ():
this.setState( (state) => {
state.array = state.array.concat([4]);
return state;
});
Ce qui suit montre ce que https://jsbin.com/mofekakuqi/7/edit?js, sortie comme un exemple de ce qui se passe si vous vous trompez.
L'appel setTimeout () ajoute correctement trois éléments car React ne mettra pas à jour par lots dans un rappel setTimeout (voir https://groups.google.com/d/msg/reactjs/G6pljvpTGX0/0ihYw2zK9dEJ).
Le buggy onClick ajoutera seulement "troisième", mais le fixe, ajoutera F, S et T comme prévu.
class List extends React.Component {
constructor(props) {
super(props);
this.state = {
array: []
}
setTimeout(this.addSome, 500);
}
addSome = () => {
this.setState(
update(this.state, {array: {$push: ["First"]}}));
this.setState(
update(this.state, {array: {$push: ["Second"]}}));
this.setState(
update(this.state, {array: {$push: ["Third"]}}));
};
addSomeFixed = () => {
this.setState( (state) =>
update(state, {array: {$push: ["F"]}}));
this.setState( (state) =>
update(state, {array: {$push: ["S"]}}));
this.setState( (state) =>
update(state, {array: {$push: ["T"]}}));
};
render() {
const list = this.state.array.map((item, i) => {
return <li key={i}>{item}</li>
});
console.log(this.state);
return (
<div className='list'>
<button onClick={this.addSome}>add three</button>
<button onClick={this.addSomeFixed}>add three (fixed)</button>
<ul>
{list}
</ul>
</div>
);
}
};
ReactDOM.render(<List />, document.getElementById('app'));
Comme @nilgun mentionné dans le commentaire, vous pouvez utiliser les aides react immutabilité . J'ai trouvé que c'était super utile.
À partir des documents:
Simple poussée
var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
initialArray est toujours [1, 2, 3].
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)})
})