React.js, warten Sie, bis setState beendet ist, bevor Sie eine Funktion auslösen?

104

Hier ist meine Situation:

  • on this.handleFormSubmit () Ich führe this.setState () aus
  • In this.handleFormSubmit () rufe ich this.findRoutes () auf. - was vom erfolgreichen Abschluss von this.setState () abhängt
  • this.setState (); wird nicht abgeschlossen, bevor this.findRoutes aufgerufen wird ...
  • Wie warte ich, bis this.setState () in this.handleFormSubmit () beendet ist, bevor ich this.findRoutes () aufrufe?

Eine unterdurchschnittliche Lösung:

  • Setzen von this.findRoutes () in componentDidUpdate ()
  • Dies ist nicht akzeptabel, da es weitere Statusänderungen gibt, die nicht mit der Funktion findRoutes () zusammenhängen. Ich möchte die Funktion findRoutes () nicht auslösen, wenn der Status ohne Bezug aktualisiert wird.

Bitte beachten Sie das folgende Code-Snippet:

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

Antworten:

245

setState()hat einen optionalen Rückrufparameter, den Sie dafür verwenden können. Sie müssen Ihren Code nur geringfügig ändern:

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

Beachten Sie, dass sich der Aufruf von findRoutesjetzt setState()als zweiter Parameter im Aufruf befindet .
Ohne, ()weil Sie die Funktion übergeben.

Winter
quelle
2
Tolle! Vielen Dank
Malexander
Dies funktioniert gut, um einen AnimatedValue nach setState in ReactNative zurückzusetzen.
SacWebDeveloper
Großartig ~ Vielen Dank
吳 強 福
2
Eine generische Versionthis.setState({ name: "myname" }, function() { console.log("setState completed", this.state) })
Sasi Varunan
Es sieht nicht so aus, als könnten Sie mehr als einen Rückruf an setState übergeben. Gibt es eine unkomplizierte Möglichkeit, Rückrufe zu verketten? Nehmen wir an, ich habe 3 Methoden, die alle ausgeführt werden müssen, und alle Aktualisierungsstatus. Was ist der bevorzugte Weg, um damit umzugehen?
Sean
17
       this.setState(
        {
            originId: input.originId,
            destinationId: input.destinationId,
            radius: input.radius,
            search: input.search
        },
        function() { console.log("setState completed", this.state) }
       )

Dies könnte hilfreich sein

Harshit Singhai
quelle
10

Laut den Dokumenten des setState()neuen Status wird möglicherweise nicht in der Rückruffunktion wiedergegeben findRoutes(). Hier ist der Auszug aus den React-Dokumenten :

setState () mutiert this.state nicht sofort, sondern erstellt einen ausstehenden Statusübergang. Der Zugriff auf this.state nach dem Aufrufen dieser Methode kann möglicherweise den vorhandenen Wert zurückgeben.

Es gibt keine Garantie für den synchronen Betrieb von Aufrufen an setState, und Anrufe können zur Leistungssteigerung gestapelt werden.

Ich schlage vor, dass Sie Folgendes tun sollten. Sie sollten die neuen Zustände inputin der Rückruffunktion übergeben 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
}

Die findRoutes()Funktion sollte folgendermaßen definiert werden:

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
}
Pawan Samdani
quelle
Dies hat einen schwerwiegenden Fehler - ein wörtliches Ziel zu übergeben, setState()da der neue Staat nicht gut ist, weil es zu Rennbedingungen führt
Teer
Hier ist ein weiteres Zitat aus den Reaktionsdokumenten (die möglicherweise aktualisiert wurden, seit Sie Ihre Antwort veröffentlicht haben): "... verwenden Sie componentDidUpdate oder einen setState-Rückruf (setState (Updater, Rückruf)), die nach dem Update garantiert ausgelöst werden angewendet wurde ". Dies sagt mir, dass sich der neue Zustand definitiv in der Rückruffunktion widerspiegelt.
Andy