DEV Community

Silviu Technology
Silviu Technology

Posted on

React: valida email sin frenar el formulario

En muchos formularios, validar el email ya no es solo revisar si existe una @. Tambien queremos detectar dominios mal escritos, evitar cuentas duplicadas y, a veces, comprobar si cierta direccion ya fue usada. El problema es que metemos todo eso en el mismo onChange, y de pronto el campo mas simple del signup se vuelve el mas pesado. Se siente medio torpe, la verdad.

Lo he visto bastante en productos hechos con React: escribes dos letras, aparece un spinner, desaparece, vuelve, cambia el helper text y la persona deja de confiar. No es que la red sea lentisima; es que el componente comunica mal la espera. Si ademas haces pruebas con un correo de usar y tirar para QA, esa friccion se nota mas porque repites el flujo varias veces y el ruido cansa rapido.

Por que la validacion lenta se siente peor de lo que es

La percepcion de velocidad importa mucho. Segun el Nielsen Norman Group, cuando una respuesta pasa de 1 segundo el usuario ya nota una pausa clara. En un campo de email, ese segundo parece aun mas largo porque ocurre mientras la persona sigue escribiendo.

Por eso intento separar una pregunta tecnica de una pregunta de experiencia: no solo "cuanto tarda la verificacion?", sino "cuando conviene molestar con esa verificacion?". Son cosas distintas, y a veces las mezclamos un poco feo.

Tambien ayuda mirar como otros equipos hacen probar emails aislados sin mezclar corridas. Aunque ese caso va mas por QA y cohortes, la leccion sirve igual: si separas estados y contexto, entiendes mejor que esta pasando y evitas conclusiones raras.

Separar formato, disponibilidad y estado pendiente

Mi regla es simple:

  1. formato: corre local y responde al instante
  2. disponibilidad: corre con debounce y solo cuando el formato ya es valido
  3. estado pendiente: se muestra sin bloquear el resto del formulario

Ese corte reduce bastante trabajo innecesario. Tambien deja mas claro que parte del feedback es definitiva y cual todavia esta "pensando". Parece un detalle chico, pero cambia la sensacion de control.

import { useEffect, useState } from "react";

export function EmailField({ value, onChange }) {
  const [formatError, setFormatError] = useState("");
  const [availability, setAvailability] = useState("idle");

  useEffect(() => {
    const valid = /\S+@\S+\.\S+/.test(value);
    setFormatError(valid || !value ? "" : "Escribe un email valido");

    if (!valid) {
      setAvailability("idle");
      return;
    }

    const timer = setTimeout(async () => {
      setAvailability("checking");
      const exists = await checkEmailAvailability(value);
      setAvailability(exists ? "taken" : "free");
    }, 350);

    return () => clearTimeout(timer);
  }, [value]);

  return (
    <label className="field">
      <span>Email</span>
      <input
        type="email"
        value={value}
        onChange={(event) => onChange(event.target.value)}
        aria-invalid={Boolean(formatError || availability === "taken")}
        aria-describedby="email-status"
      />
      <span id="email-status">
        {formatError ||
          (availability === "checking" && "Comprobando disponibilidad...") ||
          (availability === "taken" && "Ese email ya existe") ||
          " "}
      </span>
    </label>
  );
}
Enter fullscreen mode Exit fullscreen mode

No es un componente exotico ni nada. La gracia esta en que no detienes a la persona mientras esperas la llamada remota. Si el boton de submit necesita bloquearse, prefiero hacerlo por una regla clara del formulario completo, no por cada pulsacion. Si no, el campo empieza a pelearse con el resto de la UI y queda bastante meh.

Un patron simple en React para no bloquear

Cuando el chequeo remoto depende de un backend o de una cola, me funciona mejor tratar el estado pendiente como informacion auxiliar, no como alarma. Eso evita el clasico spinner ansioso que entra demasiado pronto. Tambien reduce renderizados bobos si el usuario pega el email entero de una sola vez.

En equipos donde los flujos de confirmacion son delicados, me gusta conectar esta idea con practicas de validar correos antes de tocar produccion. El contexto es otro, claro, pero la disciplina es parecida: validar con señales utiles, no con ruido.

Un detalle practico: si en tus tests usas cadenas raras como tepm mail com o tamp mail com para revisar sugerencias, no mezcles esa heuristica con la validacion principal. La sugerencia de dominio puede ser amable; la comprobacion real debe seguir siendo predecible. Si juntas ambas cosas en el mismo mensaje, el usuario no sabe si el problema es tipografico, de negocio o de red. Y ahi ya arrancamos mal.

Accesibilidad y rendimiento en el mismo componente

La parte accesible no viene despues. Va dentro del patron:

  • aria-describedby para que el estado del campo tenga contexto
  • una zona de mensaje persistente para que el layout no salte
  • debounce corto para bajar ruido de red
  • texto distinto para "invalido", "comprobando" y "ocupado"

Si quieres hilar fino, puedes medirlo. En una prueba interna muy simple, este cambio suele bajar consultas innecesarias porque solo dispara la verificacion cuando el formato ya paso. No te doy un numero magico porque depende muchisimo del producto, pero normalmente se nota en trazas, y tambien en la calma del formulario, que no siempre medimos pero deberiamos un poco mas.

Otra cosa: no marques error de disponibilidad mientras el usuario aun esta escribiendo. Ese feedback prematuro parece rapido, pero en realidad distrae. Peor aun en movil, donde cada cambio visual ocupa mas espacio y el teclado ya te roba media pantalla. Ahi cualquier detallito pesa.

Preguntas que me hago antes de darlo por bueno

Antes de cerrar un campo asi, suelo revisar esto:

  • el mensaje cambia sin mover el layout?
  • el input sigue usable si la red tarda dos segundos?
  • el submit explica por que se bloquea, si se bloquea?
  • el lector de pantalla oye estados diferentes y utiles?

Q&A rapida

Debo validar disponibilidad en cada tecla?

No. Casi nunca compensa. Mejor despues de un debounce corto y solo con formato valido.

Y si el backend falla?

Muestra un estado neutro o reintento suave. No conviertas una duda de red en un error del usuario, eso se siente injusto nomas.

Sirve para cualquier formulario?

Sirve bastante en signup, invitaciones y recovery. En otros casos, quizá con validar formato basta y ya.

Cuando el campo de email deja de comportarse como mini app independiente, todo el formulario respira mejor. React no necesita hacer trucos enormes para esto. Solo hace falta separar responsabilidades, comunicar espera con un poco de tacto y recordar que rendimiento tambien es una sensacion, no solo una metrica.

Top comments (0)