Crear formularios de reacción en 2020

Hola Habr Les presento la traducción del artículo "Creando formularios en React in 2020" por Kristofer Selbekk

imagen


Campos de entrada Áreas de texto. Botones de radio y casillas de verificación. Estos son algunos de los principales puntos de interacción que nosotros, como desarrolladores, tenemos con nuestros usuarios. Los colocamos en el sitio, los usuarios los completan y, si tenemos suerte, los formularios completados nos llegan sin errores de validación.

El procesamiento de formularios es una parte integral de una gran cantidad de aplicaciones web, y esta es una de las cosas que React hace mejor. Tienes gran libertad para crear y procesar formularios. ¿Pero hay una mejor manera de hacer esto?

Tenga en cuenta que en todos estos ejemplos crearemos un formulario de inicio de sesión con un campo de correo electrónico y contraseña, pero estos métodos se pueden usar con la mayoría de los tipos de formularios.

Recuerda las reglas de buena forma.


Aunque esto no está directamente relacionado con el tema en discusión, quiero asegurarme de que no se haya olvidado de hacer que sus formularios sean comprensibles para todos. Agregue etiquetas a sus campos de entrada, establezca los atributos de aria correctos para los casos en que la entrada no sea válida y estructura su contenido semánticamente correctamente. Esto facilita el uso de su formulario tanto para usuarios como para desarrolladores.

Procesamiento de formularios con gancho de estado


Para comenzar, veamos cómo trabajo habitualmente con el estado de formulario. Guardo todos los campos como elementos de estado separados y los actualizo todos por separado, que se parece a esto:

function LoginForm() {
  const [email, setEmail] = React.useState('');
  const [password, setPassword] = React.useState('');

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    api.login(email, password);
  };
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor='email'>Email</label>
        <input type='email' id='email' value={email} onChange={(e) => setEmail(e.target.value)} />
      </div>
      <div>
        <label htmlFor='password'>Password</label>
        <input type='password' id='password' value={password} onChange={(e) => setPassword(e.target.value)} />
      </div>
    </form>
  );
}

Primero, creo dos partes separadas del estado: nombre de usuario y contraseña. Estas dos variables se transfieren al campo de entrada correspondiente, determinando el valor de este campo. Cada vez que algo cambia en un campo, estamos seguros de actualizar el valor del estado, causando un redibujo de nuestra aplicación.

Este procesamiento de formularios funciona bien en la mayoría de los casos y es simple y fácil de usar y comprender. Sin embargo, es bastante tedioso escribir tal construcción cada vez.

Crear un gancho personalizado


Hagamos un poco de refactorización y creemos nuestro propio gancho, que mejorará ligeramente nuestro código:

const useFormField = (initialValue: string = '') => {
  const [value, setValue] = React.useState(initialValue);
  const onChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => setValue(e.target.value), []);
  return { value, onChange };
};

export function LoginForm() {
  const emailField = useFormField();
  const passwordField = useFormField();

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    api.login(emailField.value, passwordField.value);
  };
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor='email'>Email</label>
        <input type='email' id='email' {...emailField} />
      </div>
      <div>
        <label htmlFor='password'>Password</label>
        <input type='password' id='password' {...passwordField} />
      </div>
    </form>
  );
}

Creamos un enlace personalizado useFormField que crea un controlador de eventos onChange para nosotros y también almacena el valor en el estado del formulario. En este caso, podemos usar nuestro enlace con todos los campos del formulario.

Procesando una gran cantidad de campos


La desventaja de este enfoque es que no se escala bien a medida que crece su forma. Para formularios pequeños como inicio de sesión, esto probablemente sea bueno, pero cuando crea formularios de perfil de usuario puede que necesite solicitar mucha información. ¿Deberíamos llamar a nuestro gancho una y otra vez?

Cada vez que encuentro una situación similar, tiendo a escribir un gancho personalizado que almacena todos mis formularios en un fragmento grande. Podría verse así:

export function LoginForm() {
  const { formFields, createChangeHandler } = useFormFields({
    email: '',
    password: '',
  });

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    api.login(formFields.email, formFields.password);
  };
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor='email'>Email</label>
        <input type='email' id='email' value={formFields.email} onChange={createChangeHandler('email')} />
      </div>
      <div>
        <label htmlFor='password'>Password</label>
        <input type='password' id='password' value={formFields.password} onChange={createChangeHandler('password')} />
      </div>
    </form>
  );
}

Con el enlace useFormFields, podemos continuar agregando campos sin agregar complejidad a nuestro componente. Podemos acceder a todos los estados de formulario en un solo lugar, y nuestro código se ve ordenado y conciso. Por supuesto, probablemente necesite usar setState para algunas situaciones, pero para la mayoría de las formas la técnica anterior está bien.

Enfoque alternativo


Por lo tanto, el manejo del estado funciona bien y, en la mayoría de los casos, este es el enfoque preferido en React. ¿Pero sabías que hay otra manera? Resulta que el navegador por defecto procesa el estado interno del formulario, ¡y podemos usar esto para simplificar nuestro código!

Aquí está el mismo formulario, pero permitiendo que el navegador maneje el estado del formulario:

export function LoginForm() {
  const handleSubmit = (e: React.FormEvent) => {
	e.preventDefault();
	const formData = new FormData(e.target as HTMLFormElement);
	api.login(formData.get('email'), formData.get('password'));
  };
  return (
	<form onSubmit={handleSubmit}>
  	<div>
    	<label htmlFor="email">Email</label>
    	<input
      	type="email"
      	id="email"
      	name="email"
    	/>
  	</div>
  	<div>
    	<label htmlFor="password">Password</label>
    	<input
      	type="password"
      	id="password"
      	name="password"
    	/>
  	</div>
  	<button>Log in</button>
	</form>
  );
}

¡Mira lo fácil que es! No se utilizó un solo gancho, no hay una configuración de valor inicial, no hay un controlador onChange. La mejor parte es que el código todavía funciona como antes, pero ¿cómo?

Es posible que haya notado que estamos haciendo algo un poco diferente en la función handleSubmit. Utilizamos la API de navegador incorporada llamada FormData. ¡FormData es una forma conveniente (y bien soportada) de obtener valores de nuestros campos de entrada!

Obtenemos un enlace al formulario en el DOM a través del atributo de destino del evento de envío y creamos una nueva instancia de la clase FormData. Ahora podemos obtener todos los campos por su atributo de nombre llamando a formData.get ("nombre del campo de entrada").

De esa manera, nunca necesita manejar explícitamente el estado del formulario. Si necesita valores predeterminados (por ejemplo, si cambia los valores de campo iniciales de una base de datos o almacenamiento local), React le proporciona una opción conveniente de Valor predeterminado para esto.

Cuándo usar cada enfoque


Dado que los formularios son una parte integral de la mayoría de las aplicaciones web, es importante saber cómo manejarlos. Y React te ofrece muchas formas de hacerlo.
Para formularios simples que no requieren una validación rigurosa (o que pueden depender de los controles de validación de formularios HTML5 ), le sugiero que simplemente use el manejo de estado incorporado que el DOM nos proporciona de manera predeterminada. Hay bastantes cosas que no puede hacer (por ejemplo, cambiar programáticamente los valores de entrada o verificar en tiempo real), pero en los casos más simples (por ejemplo, un campo de búsqueda o un campo de inicio de sesión, como se indicó anteriormente), probablemente lo encontrará adecuado Nuestro enfoque alternativo utilizando la API del navegador.

Cuando realiza una verificación personalizada o necesita acceso a algunos datos del formulario antes de enviarlo, debe procesar explícitamente el estado utilizando componentes controlados. Puede usar useStateHooks regulares o crear un enlace personalizado para simplificar un poco su código.

Vale la pena señalar que los desarrolladores de React recomiendan el uso de componentes controlados (manejan explícitamente el estado del componente) en la mayoría de los casos, ya que este enfoque le brinda más flexibilidad en el futuro. En mi opinión, los desarrolladores a menudo sacrifican la simplicidad en aras de la flexibilidad, que a menudo no necesitan.

Cualquiera sea el enfoque que decida utilizar, el procesamiento de formularios React nunca ha sido tan fácil como lo es hoy. Puede dejar que el navegador maneje formularios simples, mientras que al mismo tiempo procesa explícitamente el estado de los formularios cuando la situación lo requiera. Espero que los métodos anteriores sean útiles y lo ayuden a resolver el problema al reducir la cantidad de líneas en su código.

All Articles