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

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.


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


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
}

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.