cover

Componentes controlados con onChange

author photo

Héctorbliss

@hectorbliss


robot logo saying hello

No te quedes atrás: Actualízate

Suscríbete para recibir información sobre nuevos frameworks, updates, eventos, tips, hacks y más.

Existen hoy en día dos formas de aproximarse a los inputs controlados.

Cada una de estas maneras trae consigo un par de beneficios que tú tendrás que decidir si son los que prefieres para ti.

Vamos, pues, a explorar las dos principales maneras de controlar un formulario. En esta learning exploraremos la más clásica: onChange

¿Muchos estados o un solo estado?

Para controlar los datos que el usuario inserta en nuestros formularios, primero tenemos que crear un estado para cada input y después, manualmente, colocar un listener en cada input para lograr pasar el value del input a cada uno de los estados asignados.

Supongamos entonces que tenemos un formulario relativamente simple, el de un SignUp:

export default function App() { return ( <form style={ { display:'flex', flexDirection:'column', maxWidth:320, marginInline:'auto', gap:8 }}> <label htmlFor="name"> Escribe tu nombre </label> <input name="name" /> <label htmlFor="email"> Escribe tu correo electrónico </label> <input name="email" type="email" /> <label htmlFor="password"> Escribe tu contraseña </label> <input name="password" type="password" /> <label htmlFor="confirm"> Repite tu contraseña </label> <input name="confirm" type="password" /> <button> Unirme </button> </form> ) }

Nuestro objetivo es tener un estado para cada input. Esto lo podemos conseguir si declaramos un useState para cada uno de los inputs:

const [email,setEmail]=useState('');

Pero esto sería escribir muchas declaraciones y tendríamos que crear una función para cada actualización.

Mejor hagamos un estado que tenga la forma de un objeto y coloquemos ahí todas las llaves necesarias:

const [form,setForm]=useState({ name:'', email:'', password:'', confirm:'', });

De esta forma, nos ahorramos escritura y al mismo tiempo tenemos una sola fuente de verdad. Es momento de meter lo que el usuario escriba en cada input.

onChange en cada input

Para lograr introducir el value de cada input en nuestro estado en la llave correcta, necesitamos colocar una función en onChange. Hay varias maneras de hacerlo, te voy a mostrar dos: una para entender qué sucede y otra que nos va a ahorrar código y trabajo:

<input name="name" onChange={(event)=>{ const {value} = event.target; setForm({...form, name:value}); }} />

Observa dos cosas, primero, ¿qué está pasando?, y después, qué podrías convertir en dinámico para no tener que escribir este callback en cada input y mejor pasar una función genérica:

<input name="name" onChange={handleChange} />

Algo así, ¿recuerdas los handlers de eventos? Como te habrás dado cuenta, escribir en cada input es tedioso en sí mismo, pero podemos aligerar la tarea definiendo un handleChange que sea capaz de asignar el value de cada input a su correspondiente estado:

const handleChange = (event) => { // El target es el input correspondiente const {name,value} = event.target; // Guardamos en el estado correspondiente usando name setForm({...form,[name]:value}); // Recuerda que los ... son el spread operator // Su función aquí, es sacar las llaves del objeto form y colocarlas una por una en este nuevo objeto que se le entrega a setForm, esto seria algo similar: // const newForm = {...form, [name]:value}; // setForm(newForm); }

Ahora, con esta función dinámica que utiliza el name del input, podemos colocarla en todos los inputs sin mayor trabajo.

<input name="email" type="email" onChange={handleChange} />

👀 ¡Ojo!, la función handleChange es muy directa, se puede simplificar en un oneliner: const hc=ev=>setForm(form=>({...form,[ev.target.name]:ev.target.value})) observa también que se puede usar el callback que nos entrega setForm, lo cual es mejor.

Por último, debemos darle el value a cada input

Para convertir nuestros inputs en verdaderamente controlados, es necesario entregarles el value, asegurándonos de que sea el correspondiente:

<input value={form.name} name="name" onChange={handleChange} /> <input value={form.email} name="email" type="email" onChange={handleChange} /> <input value={form.password} name="password" type="password" onChange={handleChange} /> <input value={form.confirm} name="confirm" type="password" onChange={handleChange} />

Hemos colocado el prop value en cada uno de nuestros inputs lo que los convierte en realmente controlados, pues ahora no pueden mostrar otra cosa que no sea el estado asignado, y solo puede cambiar por medio del onChange. Asegúrate de siempre incluir este par: value y onChange en un input controlado.

Confirmando que lo hicimos bien

Para saber que todo está en orden y que ahora tenemos almacenados los datos que el usuario ingresa, en un estado, vamos a interceptar el evento submit del formulario evitando que refresque la página (que es su acción por default) y usando el evento para mandar a consola nuestro objeto de datos.

return ( <form onSubmit={handleSubmit} ...

Colocamos el handler en el onSubmit del formulario e interceptamos:

const handleSubmit = (event) => { event.preventDefault(); console.log("form: ", form) }

Observa cómo recibimos el evento y usamos el método preventDefault para evitar que la página se refresque

👀 ¡Ojo!, la página naturalmente busca actualizarse, pues busca comunicarse con el servidor web y entregar el formulario, pero en React, cuando trabajamos en un SPA (single page application) la comunicación con el servidor no sucede en primer plano con request-response, sucede en segundo plano, con fetch.

onSubmit Si rellenas todos los campos y finalmente le damos submit con el botón, vemos en consola nuestro objeto con todos los datos correctamente asignados.

De esta forma tienes un formulario controlado, a forma de resumen es importante no olvidar:

  1. Cada input debe tener su llave name
  2. Crear una función handleChange
  3. Definir la actualización dinámica de cada llave en el objeto state
  4. Asignar esta función a cada input
  5. Crear una función handleSubmit y evitar el default del evento
  6. Asignarla al form
  7. Ahora puedes hacer lo que prefieras con los datos 🎉

Links relacionados

Código del ejemplo

React docs

Juega con React


Happy coding 🕹

banner

¿Quieres mantenerte al día sobre los próximos cursos y eventos?

Suscríbete a nuestro newsletter

Jamás te enviaremos spam, nunca compartiremos tus datos y puedes cancelar tu suscripción en cualquier momento 😉

robot logo saying hello
facebook icontwitter iconlinkedin iconinstagram iconyoutube icon

© 2016 - 2023 Fixtergeek