web-dev-qa-db-fra.com

React.js, attendez que setState se termine avant de déclencher une fonction?

Voici ma situation:

  • on this.handleFormSubmit () J'exécute this.setState ()
  • dans this.handleFormSubmit (), j'appelle this.findRoutes (); - qui dépend de la réussite de this.setState ()
  • this.setState (); ne se termine pas avant que this.findRoutes soit appelé ...
  • Comment puis-je attendre que this.setState () à l'intérieur de this.handleFormSubmit () se termine avant d'appeler this.findRoutes ()?

Une solution inférieure à la normale:

  • mettre this.findRoutes () dans composantDidUpdate ()
  • ce n'est pas acceptable car il y aura plus de changements d'état sans lien avec la fonction findRoutes (). Je ne veux pas déclencher la fonction findRoutes () lorsqu'un état non lié est mis à jour.

S'il vous plaît voir l'extrait de code ci-dessous:

handleFormSubmit: function(input){
                // Form Input
                this.setState({
                    originId: input.originId,
                    destinationId: input.destinationId,
                    radius: input.radius,
                    search: input.search
                })
                this.findRoutes();
            },
            handleMapRender: function(map){
                // Intialized Google Map
                directionsDisplay = new google.maps.DirectionsRenderer();
                directionsService = new google.maps.DirectionsService();
                this.setState({map: map});
                placesService = new google.maps.places.PlacesService(map);
                directionsDisplay.setMap(map);
            },
            findRoutes: function(){
                var me = this;
                if (!this.state.originId || !this.state.destinationId) {
                    alert("findRoutes!");
                    return;
                }
                var p1 = new Promise(function(resolve, reject) {
                    directionsService.route({
                        Origin: {'placeId': me.state.originId},
                        destination: {'placeId': me.state.destinationId},
                        travelMode: me.state.travelMode
                    }, function(response, status){
                        if (status === google.maps.DirectionsStatus.OK) {
                            // me.response = response;
                            directionsDisplay.setDirections(response);
                            resolve(response);
                        } else {
                            window.alert('Directions config failed due to ' + status);
                        }
                    });
                });
                return p1
            },
            render: function() {
                return (
                    <div className="MapControl">
                        <h1>Search</h1>
                        <MapForm
                            onFormSubmit={this.handleFormSubmit}
                            map={this.state.map}/>
                        <GMap
                            setMapState={this.handleMapRender}
                            originId= {this.state.originId}
                            destinationId= {this.state.destinationId}
                            radius= {this.state.radius}
                            search= {this.state.search}/>
                    </div>
                );
            }
        });
77
malexanders

setState() possède un paramètre de rappel facultatif que vous pouvez utiliser à cet effet. Il vous suffit de modifier légèrement votre code, à ceci:

// Form Input
this.setState(
  {
    originId: input.originId,
    destinationId: input.destinationId,
    radius: input.radius,
    search: input.search
  },
  this.findRoutes         // here is where you put the callback
);

Notez que l'appel à findRoutes est maintenant dans l'appel setState(), en tant que deuxième paramètre.
Sans () parce que vous passez la fonction.

201
wintvelt
       this.setState(
        {
            originId: input.originId,
            destinationId: input.destinationId,
            radius: input.radius,
            search: input.search
        },
        function() { console.log("setState completed", this.state) }
       )

cela pourrait être utile

11
Harshit Singhai

Selon la documentation de setState(), le nouvel état pourrait ne pas être reflété dans la fonction de rappel findRoutes(). Voici l'extrait de React docs :

setState () ne mute pas immédiatement this.state mais crée une transition d'état en attente. Accéder à this.state après avoir appelé cette méthode peut potentiellement renvoyer la valeur existante.

Il n'y a aucune garantie de fonctionnement synchrone des appels à setState et les appels peuvent être mis en lot pour des gains de performances.

Voici donc ce que je vous propose de faire. Vous devez passer les nouveaux états input dans la fonction de rappel findRoutes().

handleFormSubmit: function(input){
    // Form Input
    this.setState({
        originId: input.originId,
        destinationId: input.destinationId,
        radius: input.radius,
        search: input.search
    });
    this.findRoutes(input);    // Pass the input here
}

La fonction findRoutes() devrait être définie comme ceci:

findRoutes: function(me = this.state) {    // This will accept the input if passed otherwise use this.state
    if (!me.originId || !me.destinationId) {
        alert("findRoutes!");
        return;
    }
    var p1 = new Promise(function(resolve, reject) {
        directionsService.route({
            Origin: {'placeId': me.originId},
            destination: {'placeId': me.destinationId},
            travelMode: me.travelMode
        }, function(response, status){
            if (status === google.maps.DirectionsStatus.OK) {
                // me.response = response;
                directionsDisplay.setDirections(response);
                resolve(response);
            } else {
                window.alert('Directions config failed due to ' + status);
            }
        });
    });
    return p1
}
8
Pawan Samdani