El estado como una instantánea
Las variables de estado pueden parecer variables regulares de JavaScript a las que puedes leer y escribir. Sin embargo, el estado se comporta más como una instantánea. Establecerlo no cambia la variable de estado que ya tienes, sino que desencadena una nueva renderización.
Aprenderás
- Cómo establecer el estado desencadena nuevas renderizaciones
- Cuándo y cómo se actualiza el estado
- Por qué el estado no se actualiza inmediatamente después de establecerlo
- Cómo los manejadores de eventos acceden a una "instantánea" del estado
Establecer el estado desencadena renderizaciones
Podrías pensar que tu interfaz de usuario cambia directamente en respuesta a un evento del usuario, como un clic. En React, funciona un poco diferente de este modelo mental. En la página anterior, viste queestablecer el estado solicita una nueva renderizaciónde React. Esto significa que para que una interfaz reaccione al evento, necesitasactualizar el estado.
En este ejemplo, cuando presionas "enviar",setIsSent(true)le dice a React que vuelva a renderizar la interfaz de usuario:
Esto es lo que sucede cuando haces clic en el botón:
- El manejador de eventos
onSubmitse ejecuta. setIsSent(true)estableceisSententruey encola una nueva renderización.- React vuelve a renderizar el componente de acuerdo con el nuevo valor de
isSent.
Echemos un vistazo más de cerca a la relación entre el estado y la renderización.
La renderización toma una instantánea en el tiempo
"Renderizar"significa que React está llamando a tu componente, que es una función. El JSX que devuelves de esa función es como una instantánea de la interfaz de usuario en un momento dado. Sus props, manejadores de eventos y variables locales se calcularonutilizando su estado en el momento de la renderización.
A diferencia de una fotografía o un fotograma de película, la "instantánea" de la interfaz de usuario que devuelves es interactiva. Incluye lógica como manejadores de eventos que especifican lo que sucede en respuesta a las entradas. React actualiza la pantalla para que coincida con esta instantánea y conecta los manejadores de eventos. Como resultado, presionar un botón activará el manejador de clics de tu JSX.
Cuando React vuelve a renderizar un componente:
- React llama a tu función de nuevo.
- Tu función devuelve una nueva instantánea JSX.
- React luego actualiza la pantalla para que coincida con la instantánea que devolvió tu función.
React ejecutando la función
Calculando la instantánea
Actualizando el árbol DOM
Ilustrado porRachel Lee Nabors
Como memoria de un componente, el estado no es como una variable regular que desaparece después de que tu función devuelve un valor. El estado realmente "vive" en React mismo—¡como si estuviera en un estante!—fuera de tu función. Cuando React llama a tu componente, te da una instantánea del estado para esa renderización particular. Tu componente devuelve una instantánea de la interfaz de usuario con un nuevo conjunto de props y manejadores de eventos en su JSX, todo calculado¡utilizando los valores de estado de esa renderización!
Le dices a React que actualice el estado
React actualiza el valor del estado
React pasa una instantánea del valor del estado al componente
Ilustrado porRachel Lee Nabors
Aquí hay un pequeño experimento para mostrarte cómo funciona esto. En este ejemplo, podrías esperar que al hacer clic en el botón "+3" se incremente el contador tres veces porque llama asetNumber(number + 1)tres veces.
Observa lo que sucede cuando haces clic en el botón "+3":
Observa quenumbersolo se incrementa una vez por clic.
Establecer el estado solo lo cambia para elsiguienterenderizado.Durante el primer renderizado,numberera0. Por eso, en el manejadorde ese renderizadoonClick, el valor denumbersigue siendo0incluso después de llamar asetNumber(number + 1):
Esto es lo que el manejador de clic de este botón le dice a React que haga:
setNumber(number + 1):numberes0, así quesetNumber(0 + 1).- React se prepara para cambiar
numbera1en el siguiente renderizado.
- React se prepara para cambiar
setNumber(number + 1):numberes0, así quesetNumber(0 + 1).- React se prepara para cambiar
numbera1en el siguiente renderizado.
- React se prepara para cambiar
setNumber(number + 1):numberes0, así quesetNumber(0 + 1).- React se prepara para cambiar
numbera1en el siguiente renderizado.
- React se prepara para cambiar
Aunque llamaste asetNumber(number + 1)tres veces, en el manejador de eventosde este renderizado, numbersiempre es0, así que estableces el estado a1tres veces. Por eso, después de que tu manejador de eventos termina, React vuelve a renderizar el componente connumberigual a1en lugar de3.
También puedes visualizar esto sustituyendo mentalmente las variables de estado por sus valores en tu código. Dado que la variable de estadonumber es 0paraeste renderizado, su manejador de eventos se ve así:
Para el siguiente renderizado,numberes1, así que el manejador de clicde ese renderizadose ve así:
Por eso, hacer clic en el botón nuevamente establecerá el contador en2, luego en3en el siguiente clic, y así sucesivamente.
Estado a lo largo del tiempo
Bueno, eso fue divertido. Intenta adivinar qué alertará hacer clic en este botón:
Si usas el método de sustitución de antes, puedes adivinar que la alerta muestra "0":
Pero, ¿y si pones un temporizador en la alerta, para que solo se activedespuésde que el componente se vuelva a renderizar? ¿Diría "0" o "5"? ¡Adivina!
¿Sorprendido? Si usas el método de sustitución, puedes ver la "instantánea" del estado que se pasa a la alerta.
El estado almacenado en React puede haber cambiado para cuando se ejecuta la alerta, ¡pero se programó usando una instantánea del estado en el momento en que el usuario interactuó con él!
El valor de una variable de estado nunca cambia dentro de un renderizado,incluso si el código de su controlador de eventos es asíncrono. Dentro delonClick de ese renderizadoonClick, el valor denumbersigue siendo0incluso después de llamar asetNumber(number + 5). Su valor se "fijó" cuando React "tomó la instantánea" de la UI al llamar a tu componente.
Aquí hay un ejemplo de cómo esto hace que tus controladores de eventos sean menos propensos a errores de sincronización. A continuación hay un formulario que envía un mensaje con un retraso de cinco segundos. Imagina este escenario:
- Presionas el botón "Enviar", enviando "Hola" a Alicia.
- Antes de que termine el retraso de cinco segundos, cambias el valor del campo "Para" a "Bob".
¿Qué esperas que muestre elalert? ¿Mostraría "Dijiste Hola a Alicia"? ¿O mostraría "Dijiste Hola a Bob"? Haz una suposición basada en lo que sabes, y luego pruébalo:
React mantiene los valores del estado "fijos" dentro de los controladores de eventos de un renderizado.No necesitas preocuparte de si el estado ha cambiado mientras el código se está ejecutando.
Pero, ¿y si quisieras leer el estado más reciente antes de un nuevo renderizado? Querrás usar unafunción actualizadora de estado, ¡cubierta en la siguiente página!
Recapitulación
- Establecer estado solicita un nuevo renderizado.
- React almacena el estado fuera de tu componente, como si estuviera en un estante.
- Cuando llamas a
useState, React te da una instantánea del estadopara ese renderizado. - Las variables y los controladores de eventos no "sobreviven" a los re-renderizados. Cada renderizado tiene sus propios controladores de eventos.
- Cada renderizado (y las funciones dentro de él) siempre "verá" la instantánea del estado que React le dio aeserenderizado.
- Puedes sustituir mentalmente el estado en los controladores de eventos, de manera similar a cómo piensas en el JSX renderizado.
- Los controladores de eventos creados en el pasado tienen los valores del estado del renderizado en el que fueron creados.
Prueba algunos desafíos
Challenge 1 of 1:Implementa un semáforo #
Aquí hay un componente de luz de cruce peatonal que cambia cuando se presiona el botón:
Agrega una alert al manejador de clics. Cuando la luz es verde y dice “Walk”, hacer clic en el botón debería decir “Stop is next”. Cuando la luz es roja y dice “Stop”, hacer clic en el botón debería decir “Walk is next”.
¿Hay alguna diferencia si pones la alert antes o después de la llamada a setWalk?
