¿Por qué no hay una función getState asíncrona en React?
La documentación nos dice que setState es asíncrono. Bien, pero eso significa que no podemos usar this.state de manera segura y también necesitamos un getState asíncrono para respetar el orden de ejecución.
Por lo que entiendo, nunca deberíamos usar this.state y usar una función getState como esta:
getState(callback) { this.setState((prevState) => { callback(prevState) ; }); } ... this.getState((curState) => { // we now can use the current state safely }¿Algo que me esté perdiendo aquí en mi forma de pensar? ¿Por qué no existe tal función en React?
-- EDITAR --
Como me dijo un amigo mio no estaba claro y como no me convence pero la primera respuesta, analicemos algun trozo de codigo:
simpleFunc() { setState({ "counter" : 1 }); setState({ "counter" : 2 }); this.state.counter // => no garanty about the value getState((curState) => { // ensure curState.counter is 2 }); }Este ejemplo simple muestra que no podemos usar this.state directamente en todas las situaciones, ya que setState es asíncrono.
Aquí hay un contraejemplo donde se podría usar getState: http://codepen.io/Epithor/pen/ZLavWR?editors=0010#0
Respuesta corta: mala práctica, incluso no estoy seguro de que getState nos dé el actual
La solución es fácil, pero el hecho de que podamos factorizar algunas funciones y usarlas sin importar el contexto parece interesante, ¿no?
Entonces, cuando ocurren muchos eventos en un orden particular, algunos eventos cambian el estado, algunos leen el estado: ¿cómo puede estar seguro, cuando un evento lee el estado con this.state para leer el buen estado ya que todos los cambios son asíncronos?
De hecho, todo es cuestión de tiempo:
T : event 1, change state T+1ms : event 2, change state T+2ms : event 3, read state T+3ms : event 4, change stateComo no puede predecir cuándo ocurrirá exactamente el estado establecido del evento 1 o 2, ¿cómo podría garantizar que el evento 3 realmente leerá el estado establecido en el evento 2?
Respuesta corta: los eventos se ponen en cola en la pila JS, mientras que los cambios de estado se ponen en cola en la cola React interna. La cola de reacción interna se desapila por completo antes de dar la mano.
Definitivamente puedes usar this.state directamente en general . Nunca debe mutar el estado directamente ( this.state.foo = 0 ) y, en su lugar, use setState cada vez que desee mutar el estado.
Por lo general, un setState se ve así:
this.setState({ foo: 0 }) Entonces puede usar this.state.foo de manera segura, por ejemplo, en su función render() .
Sin embargo, hay una advertencia, ya que debido a la naturaleza asíncrona de setState , no tiene garantía de que tendrá acceso inmediato a this.state después de que se haya llamado a setState .
myFunc(baz) { this.setState({ foo: baz + 1 }) console.log(this.state.foo) // not guaranteed }mejor hacer
myFunc(baz) { const bazOne = baz + 1 this.setState({ foo: bazOne }) console.log(bazOne) } O use el segundo parámetro de las funciones setState , que se usa como una devolución de llamada que se ejecuta cuando finaliza la operación setState. En esa devolución de llamada, tendrá acceso al estado actualizado, es decir, this.state :
myFunc(baz) { this.setState({ foo: baz + 1 }, () => { console.log(this.state.foo) // guaranteed in callback }); }Ver: https://facebook.github.io/react/docs/react-component.html#setstate
setState es asíncrono, por lo que no puede acceder inmediatamente a la propiedad que cambió, SIN EMBARGO, hay casos en los que desea realizar una acción después de que se haya cambiado el estado, en esos casos puede hacer:
... this.state = { x = 1 } ... this.setState({ x = 2 }, () => { console.log(this.state.x) // outputs 2 });la función setState se llama en un tick en cola, por lo que puede poner en cola x número de setStates, todos se ejecutarán en el siguiente tick.
En realidad, no es un error/problema, sino una decisión de arquitectura: el state no está diseñado para usarse como una propiedad/variable/almacenamiento simple, está diseñado específicamente para usarse como interfaz/estado visual y, como tal, no necesita para ser actualizado en cada llamada. Utiliza una cola interna, por lo que si cambia el estado muchas veces antes de renderizar, en realidad lo actualizará solo una vez con el valor final y, cuando se invoque el método de render , contendrá el valor correcto.
Si simplemente necesita almacenar/recuperar información durante la ejecución o entre métodos que se ejecutan en la misma fase ( componentWillReceiveProps y shouldComponentUpdate , por ejemplo), puede usar this.anyProperty de manera segura como siempre:
componentWillReceiveProps() { this.value = 'guaranteed'; return true; } shouldComponentUpdate() { if (this.value === 'guaranteed') { console.log('will always return true'); } } componentDidUpdate() { this.value = ''; //cleanup } En el ejemplo anterior, si usó "setState" no habría garantía de que el valor siempre se actualizaría en "shouldComponentUpdate", pero no debería importar si lo usa para el propósito previsto. Se garantiza que los cambios de estado se borraron antes del tiempo de render , por lo que solo debe contener información utilizada en la fase de procesamiento, no datos transaccionales/internos para sus objetos. Eres libre de seguir usando las propiedades de los objetos como de costumbre.