DEV Community

Silviu Technology
Silviu Technology

Posted on

React: estados de email que no mienten

Una pantalla de verificación de email puede parecer sencilla: el usuario pulsa un botón, espera y ve un mensaje. El problema aparece cuando la interfaz mezcla “solicitud enviada”, “mensaje recibido” y “cuenta verificada”. Son hechos distintos, pero muchas UI los presentan como si fueran uno solo.

En proyectos frontend me resulta más fiable tratar la verificación como una pequeña máquina de estados. React se ocupa de renderizar cada estado y la capa de accesibilidad se asegura de que el cambio sea entendible para quien navega con teclado o lector de pantalla. El resultado suele ser menos brillante a primera vista, pero mucho mas honesto y fácil de probar.

El problema: enviado no significa verificado

Después de pulsar “Enviar código”, la aplicación normalmente solo sabe que aceptó una petición. Todavía no sabe si el email llegó, si el código pertenece a esta sesión o si ya fue utilizado. Mostrar “verificado” en ese momento crea una promesa que la aplicación no puede sostener.

Una consulta de prueba como temp org mail tampoco debería cambiar el estado de la interfaz. Es texto de búsqueda, no una señal de entrega ni una dirección válida. La UI debe reaccionar a eventos confiables del flujo, no a palabras parecidas.

Conviene separar, como mínimo, estos momentos:

  • idle: aún no se ha pedido un código.
  • sending: la petición está en curso.
  • sent: el servidor aceptó la petición, pero falta el mensaje.
  • checking: se está comprobando el código introducido.
  • verified: la cuenta quedó verificada.
  • error: algo falló y se puede explicar qué hacer después.

La diferencia entre sent y verified es pequeña en el código, pero enorme en la experiencia. También evita que un re-render o un doble clic convierta una respuesta antigua en un falso éxito.

Modela estados que el usuario pueda entender

No hace falta una librería de máquina de estados para empezar. Un estado discriminado hace explícitas las transiciones y permite que el diseño acompañe a la lógica:

type VerificationState =
  | { kind: "idle" }
  | { kind: "sending" }
  | { kind: "sent"; expiresAt: number }
  | { kind: "checking" }
  | { kind: "verified" }
  | { kind: "error"; message: string };
Enter fullscreen mode Exit fullscreen mode

El componente puede mostrar una instrucción diferente para cada kind. En sent, por ejemplo, debe pedir que se revise la bandeja y ofrecer “Reenviar” solo cuando corresponda. En verified, debe mostrar una confirmación final, no dejar un spinner activo por si acaso.

Para un entorno de pruebas, un buzón temporal como temp mail so puede ayudar a reproducir el flujo, pero el frontend sigue necesitando una señal clara del backend. La existencia de un buzón no equivale a que el código correcto haya sido consumido.

React y aria-live sin robar el foco

Los cambios de estado deben anunciarse sin mover el foco de forma agresiva. Un patrón útil es mantener el foco en el campo o botón que la persona está usando y añadir una región de estado:

function StatusMessage({ state }: { state: VerificationState }) {
  const message = {
    idle: "",
    sending: "Enviando el código…",
    sent: "Código enviado. Revisa tu bandeja de entrada.",
    checking: "Comprobando el código…",
    verified: "Email verificado correctamente.",
    error: state.kind === "error" ? state.message : "",
  }[state.kind];

  return (
    <p role="status" aria-live="polite">
      {message}
    </p>
  );
}
Enter fullscreen mode Exit fullscreen mode

role="status" suele ser suficiente para un cambio no urgente. Un error que impide continuar puede necesitar role="alert", pero usar alertas para cada actualización resulta demasido ruidoso. El texto debe ser corto, accionable y no desaparecer mientras alguien intenta leerlo.

Si una transición lleva a un formulario distinto, entonces sí puede tener sentido mover el foco al nuevo encabezado o al primer campo. Hazlo una sola vez, después de que el contenido exista, y no en cada render. De lo contrario el usuario esperan poder escribir y el foco vuelve al principio sin aviso.

Diseña una espera ligera y medible

Un spinner infinito es una mala explicación. Mientras el estado es sending o checking, desactiva solo la acción que no debe repetirse y conserva el resto del contexto visible. El botón puede cambiar a “Enviando…” y volver a “Reenviar código” cuando termine la respuesta.

También ayuda mostrar límites reales: “Puedes solicitar otro código cuando termine esta espera”. Si el servidor devuelve un identificador de intento o una fecha de expiración, guárdalos asociados a la sesión actual. No aceptes una respuesta de una solicitud anterior solo porque llegó mas tarde.

En el layout, reserva espacio para el mensaje de estado. Así un error no empuja el formulario de forma inesperada y se reduce el riesgo de cambios de diseño acumulados. Es el mismo principio que se aplica al CSS para errores de email sin CLS: el mensaje puede aparecer sin hacer saltar la pantalla.

La métrica útil no es únicamente cuánto tarda la petición. Observa cuántos reenvíos ocurren, cuántos códigos caducan y cuántas personas corrigen un error sin abandonar. Estos datos conectan el pulido visual con una experiencia de usuario que realmente funciona.

Pruebas de accesibilidad y estados de error

Prueba cada estado sin depender de que el flujo feliz termine bien. Con teclado, comprueba que el foco tenga un indicador visible y que se pueda llegar al botón de reenvío. Con un lector de pantalla, verifica que el cambio de sent a error se anuncie una vez y con instrucciones concretas.

En tests de React, renderiza el componente con cada kind y comprueba el texto que ve la persona. Añade un test para una respuesta tardía: una verificación antigua no debe reemplazar un estado nuevo. También vale la pena probar el doble clic y la pérdida temporal de conexión.

Las pruebas de correo sin falsos positivos complementan estas pruebas de UI. Una cubre la señal de entrega; la otra, la forma en que esa señal se comunica. Juntas dan más confianza que validar solo el color verde de un mensaje.

Preguntas frecuentes

¿Debo mover el foco cuando se envía el código?

Normalmente no. Conserva el foco donde estaba y anuncia el cambio con una región de estado. Muévelo solo si aparece un contexto nuevo que requiere interacción inmediata.

¿Puedo mostrar “verificado” cuando el servidor responde 200?

Solo si ese 200 representa la verificación completada. Si confirma únicamente que el email fue enviado, usa sent y explica el siguiente paso.

¿Qué hago con un código expirado?

Muestra un error específico, conserva el email visible y ofrece solicitar un código nuevo. Evita borrar todo el formulario: recuperar el contexto es mas amable y reduce trabajo repetido.

Una interfaz de verificación confiable no necesita ocultar la espera. Necesita nombrar cada estado, anunciar los cambios con cuidado y tratar los errores como parte normal del diseño. React hace fácil renderizar la pantalla; la calidad aparece cuando cada mensaje dice exactamente lo que la aplicación sabe.

Top comments (0)