133 votes

setState ne met pas l'état à jour immédiatement

Je voudrais demander pourquoi mon état ne change pas quand je fais un onClick événement. J'ai cherché il y a un moment que je dois lier l'évènement onClick dans le constructeur mais l'état n'est toujours pas mis à jour.

Voici mon code :

import React from 'react';
import Grid from 'react-bootstrap/lib/Grid';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import BoardAddModal from 'components/board/BoardAddModal.jsx';    
import style from 'styles/boarditem.css';

class BoardAdd extends React.Component {
    constructor(props) {
        super(props);    
        this.state = {
            boardAddModalShow: false
        };    
        this.openAddBoardModal = this.openAddBoardModal.bind(this);
    }

    openAddBoardModal() {
        this.setState({ boardAddModalShow: true }); // set boardAddModalShow to true

        /* After setting a new state it still returns a false value */
        console.log(this.state.boardAddModalShow);   
    }

    render() {    
        return (
            <Col lg={3}>
                <a href="javascript:;" 
                   className={style.boardItemAdd} 
                   onClick={this.openAddBoardModal}>
                    <div className={[style.boardItemContainer,
                                     style.boardItemGray].join(' ')}>
                        Create New Board
                    </div>
                </a>
            </Col>
        );
    }
}

export default BoardAdd

8 votes

La réponse que vous avez accepté sur cette question n'a aucun sens. setState ne renvoie pas de promesse. Si ça a marché, c'est uniquement parce que await introduit un "tick" asynchrone dans la fonction, et il est arrivé que la mise à jour de l'état a été traitée pendant ce tick. Ce n'est pas garanti. Comme cette réponse dit, vous devez utiliser le callback d'achèvement (si vous avez vraiment besoin de faire quelque chose après la mise à jour de l'état, ce qui est inhabituel ; normalement, vous voulez juste refaire le rendu, ce qui se produit automatiquement).

3 votes

Il serait bon que vous annuliez la réponse actuellement acceptée ou que vous en acceptiez une correcte, car celle-ci pourrait alors être utilisée comme doublon pour de nombreuses autres questions. Le fait d'avoir une réponse incorrecte en haut de la page est trompeur.

187voto

Shubham Khatri Points 67350

Votre état a besoin d'un certain temps pour muter, et comme console.log(this.state.boardAddModalShow) s'exécute avant que l'état ne mute, vous obtenez la valeur précédente en sortie. Vous devez donc écrire la console dans le callback de la fonction setState fonction

openAddBoardModal() {
  this.setState({ boardAddModalShow: true }, function () {
    console.log(this.state.boardAddModalShow);
  });
}

setState est asynchrone. Cela signifie que vous ne pouvez pas l'appeler sur une ligne et supposer que l'état a changé sur la suivante.

Según Documents sur React

setState() ne mute pas immédiatement this.state mais crée une transition d'état en attente. Accès à this.state après avoir appelé cette peut potentiellement retourner la valeur existante. Il n'y a pas de garantie de fonctionnement synchrone des appels à setState et les appels peuvent et les appels peuvent être groupés pour gagner en performance.

Pourquoi feraient-ils setState asynchrone

Cela s'explique par le fait que setState modifie l'état et provoque un nouveau rendu. Ce peut être une opération coûteuse et la rendre synchrone pourrait laisser le navigateur ne répond plus.

Ainsi, le setState Les appels sont asynchrones et mis en lots pour améliorer l'interface utilisateur. l'expérience utilisateur et les performances.

0 votes

Jusqu'à présent, c'est une excellente idée, mais que faire si nous ne pouvons pas utiliser console.log parce que nous utilisons les règles d'eslint ?

2 votes

@maudev, les règles eslint vous empêchent d'avoir des console.logs afin qu'ils ne se retrouvent pas en production, mais l'exemple ci-dessus est purement pour le débogage. et console.log et être remplacé par une action qui prend en compte l'état mis à jour

1 votes

Et si le callback ne fonctionne pas comme vous l'avez dit ? le mien ne fonctionne pas !

43voto

Asif J Points 787

Heureusement, setState() prend un callback. Et c'est là que nous obtenons l'état mis à jour.

Prenons cet exemple.

this.setState({ name: "myname" }, () => {                              
        //callback
        console.log(this.state.name) // myname
      });

Ainsi, lorsque le rappel se déclenche, this.state est l'état mis à jour.
Vous pouvez obtenir mutated/updated données dans le rappel.

1 votes

Vous pouvez également utiliser ce callback pour passer n'importe quelle fonction, initMap() par exemple

1 votes

C'est parti ! J'ai enfin résolu mon problème. Merci beaucoup.

13voto

Adnan shah Points 518

Puisque setSatate est une fonction asynchrone, vous devez consigner l'état en tant que callback comme ceci.

openAddBoardModal(){
    this.setState({ boardAddModalShow: true }, () => {
        console.log(this.state.boardAddModalShow)
    });
}

8voto

Aman Seth Points 100

setState() ne met pas toujours immédiatement à jour le composant. Elle peut être mise en attente ou reporter la mise à jour à plus tard. Cela rend la lecture de this.state juste après l'appel à setState() un piège potentiel. Utilisez plutôt componentDidUpdate ou un setState callback ( setState(updater, callback) ), dont le déclenchement est garanti après l'application de la mise à jour. Si vous devez définir l'état en fonction de l'état précédent, lisez l'argument updater ci-dessous.

setState() conduira toujours à un nouveau rendu, sauf si shouldComponentUpdate() renvoie un faux. Si des objets mutables sont utilisés et que la logique de rendu conditionnel ne peut pas être mise en œuvre dans le cadre de l'option shouldComponentUpdate() en appelant setState() uniquement lorsque le nouvel état diffère de l'état précédent, ce qui évitera les réexpositions inutiles.

Le premier argument est une fonction de mise à jour avec la signature :

(state, props) => stateChange

state est une référence à l'état du composant au moment où la modification est appliquée. Il ne doit pas être directement modifié. Au lieu de cela, les changements doivent être représentés par la construction d'un nouvel objet basé sur l'entrée de l'état et des props. Par exemple, supposons que nous voulions incrémenter une valeur dans state par props.step :

this.setState((state, props) => {
    return {counter: state.counter + props.step};
});

2voto

Ravin Gupta Points 147

Si vous voulez savoir si l'état est mis à jour ou non, une autre façon de procéder est la suivante

_stateUpdated(){
  console.log(this.state. boardAddModalShow);
}

openAddBoardModal(){
  this.setState(
    {boardAddModalShow: true}, 
    this._stateUpdated.bind(this)
  );
}

De cette façon, vous pouvez appeler la méthode "_stateUpdated" chaque fois que vous essayez de mettre à jour l'état pour le débogage.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X