¿Cómo puedo esperar a que termine setState antes de activar una función en React?

6 minutos de lectura

avatar de usuario
malexanders

Aquí está mi situación:

  • en this.handleFormSubmit() estoy ejecutando this.setState()
  • dentro de this.handleFormSubmit(), estoy llamando a this.findRoutes(); – que depende de la finalización exitosa de this.setState()
  • este.setState(); no se completa antes de llamar a this.findRoutes…
  • ¿Cómo espero a que termine this.setState() dentro de this.handleFormSubmit() antes de llamar a this.findRoutes()?

Una solución mediocre:

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

setState() tiene un parámetro de devolución de llamada opcional que puede usar para esto. Solo necesita cambiar su código ligeramente, a 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
);

Fíjate en la llamada a findRoutes ahora está dentro de la setState() call, como segundo parámetro.
Sin que () porque estás pasando la función.

  • Esto funcionará bien para restablecer un AnimatedValue después de setState en ReactNative.

    – Desarrollador SacWeb

    14 de febrero de 2017 a las 23:56

  • Una versión genérica this.setState({ name: "myname" }, function() { console.log("setState completed", this.state) })

    – Sasi Varunan

    8 de marzo de 2018 a las 10:33


  • No parece que pueda pasar más de una devolución de llamada a setState. ¿Existe una forma sencilla de encadenar las devoluciones de llamadas? Digamos que tengo 3 métodos que deben ejecutarse y todos los estados de actualización. ¿Cuál es la forma preferida de manejar esto?

    – sean

    1 mayo 2018 a las 20:05

  • Sin más información, creo que la devolución de llamada 1 sería un contenedor, que llama a cualquiera de sus 3 métodos (si es necesario activarlos en secuencia). O el contenedor llama a sus 3 métodos en secuencia, y luego hace uno setState() (si realmente no necesita 4 cambios de estado seguidos). ¿Podría dar más detalles sobre el caso específico de EE. UU.?

    – terciopelo

    1 mayo 2018 a las 20:20

  • Trabajó para mí… Muchas gracias.

    – Desarrollador SP

    24 de enero de 2019 a las 14:02

avatar de usuario
Furquan

Si alguien aquí aterrizó y tiene la misma situación usando ganchos, se puede lograr el mismo comportamiento a través del siguiente proceso

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

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

setData(true);

Aquí useEffect se ejecutará después de cualquier cambio en los datos, y podemos ejecutar cualquier tarea dependiente.

  • Tenga en cuenta que es posible que el desarrollador desee omitir el primer renderizado agregando una condición, ya que el código también se ejecutará en el primer renderizado

    – cibermosca

    27 de mayo a las 2:01


avatar de usuario
Harshit Singapur

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

  • Alguna explicación haría de esta una mejor respuesta. Consulte Cómo responder.

    – madera de isher

    hace 2 días

avatar de usuario
Pawan Samdani

Según los documentos de setState() es posible que el nuevo estado no se refleje en la función de devolución de llamada findRoutes(). Aquí está el extracto de Reaccionar documentos:

setState() no muta inmediatamente this.state sino que crea una transición de estado pendiente. Acceder a this.state después de llamar a este método puede potencialmente devolver el valor existente.

No hay garantía de funcionamiento síncrono de las llamadas a setState y las llamadas pueden agruparse por lotes para mejorar el rendimiento.

Así que esto es lo que te propongo que hagas. Deberías pasar los nuevos estados. input 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
}

los findRoutes() La función 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 toma el nuevo estado y la función de devolución de llamada opcional que se llama después de que se haya actualizado el estado.

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

  • Esta es una repetición de una respuesta de cuatro años antes.

    – madera de isher

    hace 2 días

avatar de usuario
HoldOffHunger

¿Por qué no una respuesta más? setState() y el setState()-motivado render() ambos han completado la ejecución cuando llamas componentDidMount() (la primera vez render() se ejecuta) y/o componentDidUpdate() (en cualquier momento después render() es ejecutado). (Los enlaces son para documentos de ReactJS.org).

Ejemplo con componentDidUpdate()

Llamante, establecer referencia y establecer estado…

<Cmp ref={(inst) => {this.parent=inst}}>;
this.parent.setState({'data':'hello!'});

Procesar padre…

componentDidMount() {           // componentDidMount() gets called after first state set
    console.log(this.state.data);   // output: "hello!"
}
componentDidUpdate() {          // componentDidUpdate() gets called after all other states set
    console.log(this.state.data);   // output: "hello!"
}

Ejemplo con componentDidMount()

Llamante, establecer referencia y establecer estado…

<Cmp ref={(inst) => {this.parent=inst}}>
this.parent.setState({'data':'hello!'});

Procesar padre…

render() {              // render() gets called anytime setState() is called
    return (
        <ChildComponent
            state={this.state}
        />
    );
}

Después de que el padre vuelve a representar al hijo, vea el estado en componentDidUpdate().

componentDidMount() {           // componentDidMount() gets called anytime setState()/render() finish
console.log(this.props.state.data); // output: "hello!"
}

  • Esta es una repetición de una respuesta de cuatro años antes.

    – madera de isher

    hace 2 días

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad