javascript - Ako môžem počkať, kým sa setState dokončí, pred spustením funkcie v React?


Tu je moja situácia:

  • na this.handleFormSubmit() vykonávam this.setState()
  • vo vnútri this.handleFormSubmit() volám this.findRoutes(); - čo závisí od úspešného dokončenia this.setState()
  • this.setState(); sa nedokončí pred tým, než sa zavolá this.findRoutes...
  • Ako čakám, kým this.setState() vo vnútri this.handleFormSubmit() skončí, predtým než zavolám this.findRoutes()?

Podpriemerné riešenie:

  • vloženie this.findRoutes() do componentDidUpdate()
  • Toto nie je prijateľné, pretože dôjde k viacerým zmenám stavu, ktoré nesúvisia s funkciou findRoutes(). Nechcem spúšťať funkciu findRoutes(), keď sa aktualizuje nesúvisiaci stav.

Prosím, pozrite si nasledujúci kódový útržok:

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

Odpoveď č. 1

Metóda setState() má voliteľný parameter callback, ktorý môžete na toto použiť. Stačí, ak trochu zmeníte svoj kód na toto:

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

Všimnite si, že volanie findRoutes je teraz vnorené do volania setState() ako druhý parameter.
Bez (), pretože odovzdávate funkciu.

Odpoveď č. 2

Ak tu niekto pristál a má rovnakú situáciu pri používaní hookov, rovnaké správanie je možné dosiahnuť prostredníctvom nasledujúceho postupu

const [data, setData] = useState(false);

useEffect(() => {
    doSomething(); // This will be executed when the state changes
}, [data]);

setData(true);

Tu sa useEffect spustí po akejkoľvek zmene v dátach a môžeme vykonať akúkoľvek závislú úlohu.

Odpoveď č. 3

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

Odpoveď č. 4

setState prijíma nový stav a voliteľnú spätnú volaciu funkciu, ktorá sa volá po aktualizácii stavu.

this.setState(
  {newState: 'whatever'},
  () => {/*do something after the state has been updated*/}
)

Odpoveď č. 5

Podľa dokumentácie setState() sa nový stav nemusí prejaviť v spätnom volaní funkcie findRoutes(). Tu je úryvok z dokumentácie React:

setState() nezmení okamžite this.state, ale vytvorí čakajúci prechod stavu. Prístup k this.state po zavolaní tejto metódy môže potenciálne vrátiť existujúcu hodnotu.

Neexistuje žiadna záruka synchronného spustenia volaní setState a volania môžu byť kvôli zvýšeniu výkonu zoskupované.

Takže tu je to, čo navrhujem, aby ste urobili. Mali by ste odovzdať nové stavy input do spätného volania 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
}

Funkcia findRoutes() by mala byť definovaná takto:

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
}

Súvisiace články