javascript - promesas - React.js, ¿espera que setState termine antes de activar una función?
programacion asincrona javascript (3)
Aquí está mi situación:
- en this.handleFormSubmit () Estoy ejecutando this.setState ()
- dentro de this.handleFormSubmit (), estoy llamando this.findRoutes (); - que depende de la finalización exitosa de this.setState ()
- this.setState (); no se completa antes de this.findRoutes se llama ...
- ¿Cómo espero a que this.setState () dentro de this.handleFormSubmit () termine antes de llamar this.findRoutes ()?
Una solución deficiente:
- poniendo this.findRoutes () en componentDidUpdate ()
- esto no es aceptable porque habrá más cambios de estado no relacionados con la función findRoutes (). No quiero activar la función findRoutes () cuando se actualiza el estado no relacionado.
Consulte el fragmento de código a continuación:
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>
);
}
});
Según los documentos de
setState()
el nuevo estado podría no reflejarse en la función de devolución de llamada
findRoutes()
.
Aquí está el extracto de
React docs
:
setState () no muta inmediatamente this.state pero crea una transición de estado pendiente. Acceder a this.state después de llamar a este método puede devolver el valor existente.
No hay garantía de operación síncrona de llamadas a setState y las llamadas pueden ser agrupadas para obtener ganancias de rendimiento.
Entonces, esto es lo que les propongo que hagan.
Debe pasar la
input
nuevos estados en la función de devolución de llamada
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 función
findRoutes()
debe definirse así:
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
}
setState()
tiene un parámetro de devolución de llamada opcional que puede usar para esto.
Solo necesita cambiar su código ligeramente, para esto:
// 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
);
Observe que la llamada a
findRoutes
ahora está dentro de la llamada
setState()
, como el segundo parámetro.
Sin
()
porque está pasando la función.
this.setState(
{
originId: input.originId,
destinationId: input.destinationId,
radius: input.radius,
search: input.search
},
function() { console.log("setState completed", this.state) }
)
esto puede ser útil