Je lis la section Forms de la documentation reactjs et viens d'essayer ce code pour démontrer l'utilisation de onChange
( JSBIN ).
var React= require('react');
var ControlledForm= React.createClass({
getInitialState: function() {
return {
value: "initial value"
};
},
handleChange: function(event) {
console.log(this.state.value);
this.setState({value: event.target.value});
console.log(this.state.value);
},
render: function() {
return (
<input type="text" value={this.state.value} onChange={this.handleChange}/>
);
}
});
React.render(
<ControlledForm/>,
document.getElementById('mount')
);
Lorsque je mets à jour la valeur <input/>
dans le navigateur, le deuxième console.log
dans le rappel handleChange
imprime la même value
que le premier console.log
. Pourquoi ne puis-je pas voir le résultat de this.setState({value: event.target.value})
dans l'étendue du rappel handleChange
?
De React's documentation :
setState()
ne mute pas immédiatementthis.state
mais crée un en attente de transition d'état. Accéder àthis.state
après avoir appelé cette méthode peut potentiellement renvoyer la valeur existante. Il n'y a pas garantie de fonctionnement synchrone des appels àsetState
et les appels peuvent être groupé pour des gains de performance.
Si vous souhaitez qu'une fonction soit exécutée après le changement d'état, transmettez-la sous forme de rappel.
this.setState({value: event.target.value}, function () {
console.log(this.state.value);
});
Comme indiqué dans la documentation de React, rien ne garantit que setState
sera déclenché de manière synchrone. Votre console.log
peut donc renvoyer l'état avant sa mise à jour.
Michael Parker mentionne avoir passé un rappel dans la setState
. Une autre façon de gérer la logique après le changement d'état consiste à utiliser la méthode componentDidUpdate
lifecycle, méthode recommandée dans la documentation de React.
En règle générale, nous vous recommandons d’utiliser ComponentDidUpdate () pour une telle logique.
Ceci est particulièrement utile lorsqu'il peut y avoir plusieurs déclenchements successifs de setState
et que vous souhaitez activer la même fonction après chaque changement d'état. Plutôt que d'ajouter un rappel à chaque setState
, vous pouvez placer la fonction à l'intérieur de la componentDidUpdate
, avec une logique spécifique à l'intérieur si nécessaire.
// example
componentDidUpdate(prevProps, prevState) {
if (this.state.value > prevState.value) {
this.foo();
}
}
Vous pouvez essayer d’utiliser ES7 async/wait. Par exemple, en utilisant votre exemple:
handleChange: async function(event) {
console.log(this.state.value);
await this.setState({value: event.target.value});
console.log(this.state.value);
}
Surveillez les méthodes de cycle de vie de réaction!
J'ai travaillé pendant plusieurs heures pour savoir que getDerivedStateFromProps
sera appelé après chaque setState()
.
????
La syntaxe async-await
fonctionne parfaitement pour quelque chose comme ce qui suit ...
changeStateFunction = () => {
// Some Worker..
this.setState((prevState) => ({
year: funcHandleYear(),
month: funcHandleMonth()
}));
goNextMonth = async () => {
await this.changeStateFunction();
const history = createBrowserHistory();
history.Push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}
goPrevMonth = async () => {
await this.changeStateFunction();
const history = createBrowserHistory();
history.Push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}
Mettre simplement - this.setState ({data: value}) est de nature asynchrone, ce qui signifie qu’il sort de la pile d’appels et ne revient dans la pile d’appels que s’il est résolu.
Veuillez lire sur Event Loop pour avoir une image claire de la nature asynchrone dans JS et des raisons pour lesquelles la mise à jour prend du temps -
https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4
Par conséquent -
this.setState({data:value});
console.log(this.state.data); // will give undefined or unupdated value
car il faut du temps pour mettre à jour. Pour réaliser le processus ci-dessus -
this.setState({data:value},function () {
console.log(this.state.data);
});