v19.2Latest

Reaccionar a la entrada con estado

React proporciona una forma declarativa de manipular la interfaz de usuario. En lugar de manipular directamente piezas individuales de la interfaz de usuario, describes los diferentes estados en los que puede estar tu componente y cambias entre ellos en respuesta a la entrada del usuario. Esto es similar a cómo piensan los diseñadores sobre la interfaz de usuario.

Aprenderás
  • Cómo difiere la programación declarativa de UI de la programación imperativa de UI
  • Cómo enumerar los diferentes estados visuales en los que puede estar tu componente
  • Cómo desencadenar los cambios entre los diferentes estados visuales desde el código

Cómo se compara la UI declarativa con la imperativa

Cuando diseñas interacciones de UI, probablemente pienses en cómo la interfaz de usuariocambiaen respuesta a las acciones del usuario. Considera un formulario que permite al usuario enviar una respuesta:

  • Cuando escribes algo en el formulario, el botón "Enviar"se habilita.
  • Cuando presionas "Enviar", tanto el formulario como el botónse deshabilitan,y aparece un indicador de carga (spinner).
  • Si la solicitud de red tiene éxito, el formulariose oculta,y aparece el mensaje "Gracias".
  • Si la solicitud de red falla, aparece un mensaje de error,aparece,y el formulariose vuelve a habilitar.

En laprogramación imperativa,lo anterior corresponde directamente a cómo implementas la interacción. Tienes que escribir las instrucciones exactas para manipular la interfaz de usuario dependiendo de lo que acaba de suceder. Aquí hay otra forma de pensar en esto: imagina ir al lado de alguien en un automóvil y decirle giro por giro a dónde ir.

En un automóvil conducido por una persona con aspecto ansioso que representa JavaScript, un pasajero ordena al conductor que ejecute una secuencia de complicadas navegaciones giro por giro.

Ilustrado porRachel Lee Nabors

Ellos no saben a dónde quieres ir, solo siguen tus comandos. (¡Y si te equivocas en las direcciones, terminas en el lugar equivocado!) Se llamaimperativoporque tienes que "ordenar" a cada elemento, desde el spinner hasta el botón, diciéndole a la computadoracómoactualizar la interfaz de usuario.

En este ejemplo de programación imperativa de UI, el formulario está construidosinReact. Solo utiliza elDOMdel navegador:

Manipular la UI de manera imperativa funciona lo suficientemente bien para ejemplos aislados, pero se vuelve exponencialmente más difícil de gestionar en sistemas más complejos. Imagina actualizar una página llena de diferentes formularios como este. Agregar un nuevo elemento de UI o una nueva interacción requeriría verificar cuidadosamente todo el código existente para asegurarte de no haber introducido un error (por ejemplo, olvidar mostrar u ocultar algo).

React fue construido para resolver este problema.

En React, no manipulas directamente la interfaz de usuario, es decir, no habilitas, deshabilitas, muestras u ocultas componentes directamente. En cambio,declaras lo que quieres mostrar,y React determina cómo actualizar la interfaz de usuario. Piensa en subir a un taxi y decirle al conductor a dónde quieres ir en lugar de decirle exactamente dónde girar. Es trabajo del conductor llevarte allí, ¡y puede que incluso conozca algunos atajos que no has considerado!

En un automóvil conducido por React, un pasajero pide ser llevado a un lugar específico en el mapa. React determina cómo hacerlo.

Ilustrado porRachel Lee Nabors

Pensar en la UI de manera declarativa

Has visto cómo implementar un formulario de manera imperativa arriba. Para comprender mejor cómo pensar en React, a continuación recorrerás la reimplementación de esta interfaz de usuario en React:

  1. Identificalos diferentes estados visuales de tu componente
  2. Determinaqué desencadena esos cambios de estado
  3. Representael estado en memoria usandouseState
  4. Eliminacualquier variable de estado no esencial
  5. Conectalos manejadores de eventos para establecer el estado

Paso 1: Identifica los diferentes estados visuales de tu componente

En informática, es posible que hayas oído hablar de una"máquina de estados"que se encuentra en uno de varios "estados". Si trabajas con un diseñador, es posible que hayas visto maquetas para diferentes "estados visuales". React se encuentra en la intersección del diseño y la informática, por lo que ambas ideas son fuentes de inspiración.

Primero, necesitas visualizar todos los diferentes "estados" de la interfaz de usuario que el usuario podría ver:

  • Vacío: El formulario tiene un botón "Enviar" deshabilitado.
  • Escribiendo: El formulario tiene un botón "Enviar" habilitado.
  • Enviando: El formulario está completamente deshabilitado. Se muestra un indicador de carga.
  • Éxito: Se muestra un mensaje de "Gracias" en lugar del formulario.
  • Error: Igual que el estado "Escribiendo", pero con un mensaje de error adicional.

Al igual que un diseñador, querrás "maquetar" o crear "maquetas" para los diferentes estados antes de agregar lógica. Por ejemplo, aquí hay una maqueta solo para la parte visual del formulario. Esta maqueta está controlada por una prop llamadastatuscon un valor predeterminado de'empty':

Puedes llamar a esa prop como quieras, el nombre no es importante. Intenta editarstatus = 'empty' a status = 'success'para ver aparecer el mensaje de éxito. La maquetación te permite iterar rápidamente en la interfaz de usuario antes de conectar cualquier lógica. Aquí hay un prototipo más completo del mismo componente, aún "controlado" por la propstatus:

Paso 2: Determina qué desencadena esos cambios de estado

Puedes desencadenar actualizaciones de estado en respuesta a dos tipos de entradas:

  • Entradas humanas,como hacer clic en un botón, escribir en un campo, navegar por un enlace.
  • Entradas de computadora,como la llegada de una respuesta de red, la finalización de un tiempo de espera, la carga de una imagen.
Un dedo.Unos y ceros.

Ilustrado porRachel Lee Nabors

En ambos casos,debes establecervariables de estadopara actualizar la interfaz de usuario.Para el formulario que estás desarrollando, necesitarás cambiar el estado en respuesta a algunas entradas diferentes:

  • Cambiar la entrada de texto(humano) debería cambiarlo del estadoVacíoal estadoEscribiendoo viceversa, dependiendo de si el cuadro de texto está vacío o no.
  • Hacer clic en el botón Enviar(humano) debería cambiarlo al estadoEnviando.
  • Una respuesta de red exitosa(computadora) debería cambiarlo al estadoÉxito.
  • Una respuesta de red fallida(computadora) debería cambiarlo al estadoErrorcon el mensaje de error correspondiente.
Nota

Observa que las entradas humanas a menudo requierenmanejadores de eventos.

Para ayudar a visualizar este flujo, intenta dibujar cada estado en papel como un círculo etiquetado, y cada cambio entre dos estados como una flecha. Puedes esbozar muchos flujos de esta manera y resolver errores mucho antes de la implementación.

Diagrama de flujo que se mueve de izquierda a derecha con 5 nodos. El primer nodo etiquetado como 'vacío' tiene una arista etiquetada 'empezar a escribir' conectada a un nodo etiquetado 'escribiendo'. Ese nodo tiene una arista etiquetada 'presionar enviar' conectada a un nodo etiquetado 'enviando', que tiene dos aristas. La arista izquierda está etiquetada 'error de red' conectando a un nodo etiquetado 'error'. La arista derecha está etiquetada 'éxito de red' conectando a un nodo etiquetado 'éxito'.Diagrama de flujo que se mueve de izquierda a derecha con 5 nodos. El primer nodo etiquetado como 'vacío' tiene una arista etiquetada 'empezar a escribir' conectada a un nodo etiquetado 'escribiendo'. Ese nodo tiene una arista etiquetada 'presionar enviar' conectada a un nodo etiquetado 'enviando', que tiene dos aristas. La arista izquierda está etiquetada 'error de red' conectando a un nodo etiquetado 'error'. La arista derecha está etiquetada 'éxito de red' conectando a un nodo etiquetado 'éxito'.

Estados del formulario

Paso 3: Representar el estado en memoria conuseState

A continuación, necesitarás representar los estados visuales de tu componente en memoria conuseState.La simplicidad es clave: cada pieza de estado es una "pieza móvil", yquieres tener la menor cantidad posible de "piezas móviles".¡Más complejidad conduce a más errores!

Comienza con el estado queabsolutamente debeestar allí. Por ejemplo, necesitarás almacenar laanswerpara la entrada, y elerror(si existe) para almacenar el último error:

Luego, necesitarás una variable de estado que represente cuál de los estados visuales quieres mostrar. Normalmente hay más de una forma de representar eso en memoria, por lo que tendrás que experimentar con ello.

Si te cuesta pensar inmediatamente en la mejor manera, comienza añadiendo suficiente estado para que estésdefinitivamenteseguro de que todos los posibles estados visuales están cubiertos:

Tu primera idea probablemente no será la mejor, pero está bien: ¡refactorizar el estado es parte del proceso!

Paso 4: Eliminar cualquier variable de estado no esencial

Quieres evitar la duplicación en el contenido del estado para que solo rastrees lo esencial. Dedicar un poco de tiempo a refactorizar la estructura de tu estado hará que tus componentes sean más fáciles de entender, reducirá la duplicación y evitará significados no deseados. Tu objetivo esprevenir los casos en los que el estado en memoria no represente ninguna interfaz de usuario válida que quieras que un usuario vea.(Por ejemplo, ¡nunca querrás mostrar un mensaje de error y deshabilitar la entrada al mismo tiempo, o el usuario no podrá corregir el error!)

Aquí hay algunas preguntas que puedes hacer sobre tus variables de estado:

  • ¿Este estado causa una paradoja?Por ejemplo,isTyping y isSubmittingno pueden ser ambostrue. Una paradoja generalmente significa que el estado no está lo suficientemente restringido. Hay cuatro combinaciones posibles de dos booleanos, pero solo tres corresponden a estados válidos. Para eliminar el estado "imposible", puedes combinarlos en unstatusque debe ser uno de tres valores:'typing','submitting', o'success'.
  • ¿La misma información ya está disponible en otra variable de estado?Otra paradoja:isEmpty y isTypingno pueden sertrueal mismo tiempo. Al hacerlas variables de estado separadas, corres el riesgo de que se desincronicen y causen errores. Afortunadamente, puedes eliminarisEmptyy en su lugar verificaranswer.length === 0.
  • ¿Puedes obtener la misma información a partir del inverso de otra variable de estado?isErrorno es necesario porque puedes verificarerror !== nullen su lugar.

Después de esta limpieza, te quedan 3 (¡reducidas de 7!) variables de estadoesenciales:

Sabes que son esenciales porque no puedes eliminar ninguna de ellas sin romper la funcionalidad.

Deep Dive
Eliminando estados “imposibles” con un reducer

Paso 5: Conectar los controladores de eventos para establecer el estado

Finalmente, crea controladores de eventos que actualicen el estado. A continuación se muestra el formulario final, con todos los controladores de eventos conectados:

Aunque este código es más largo que el ejemplo imperativo original, es mucho menos frágil. Expresar todas las interacciones como cambios de estado te permite introducir posteriormente nuevos estados visuales sin romper los existentes. También te permite cambiar lo que debe mostrarse en cada estado sin cambiar la lógica de la interacción en sí.

Recapitulación

  • La programación declarativa significa describir la UI para cada estado visual en lugar de microgestionar la UI (imperativo).
  • Al desarrollar un componente:
    1. Identifica todos sus estados visuales.
    2. Determina los desencadenantes humanos e informáticos para los cambios de estado.
    3. Modela el estado conuseState.
    4. Elimina el estado no esencial para evitar errores y paradojas.
    5. Conecta los controladores de eventos para establecer el estado.

Try out some challenges

Challenge 1 of 3:Add and remove a CSS class #

Make it so that clicking on the picture removes the background--active CSS class from the outer <div>, but adds the picture--active class to the <img>. Clicking the background again should restore the original CSS classes.

Visually, you should expect that clicking on the picture removes the purple background and highlights the picture border. Clicking outside the picture highlights the background, but removes the picture border highlight.