Introducción
No todos los elementos de formulario funcionan de la misma forma que los <input type="text">
con los que hemos estado trabajando.
Cada uno de estos elementos como <textarea>
,<input type="checkbox">
,<input type="radio">
tienen sus peculiaridades a la hora de trabajar con ellos en React.
Elementos de formulario
textarea
En HTML, la etiqueta textarea se cierra con su correspondiente etiqueta de cierre y, sea lo que sea que pongamos entre las etiquetas es su valor o value
por ejemplo:
<textarea> mi texto </textarea>
.
Sin embargo, en JSX/React, para representar un elemento textarea podemos cerrarlo en la misma etiqueta e, igual que nuestro inputs de tipo texto, le añadimos una propiedad value
por ejemplo:
<textarea value={'mi texto'}/>
Todo lo demás, que hemos aprendido previamente en el anterior artículo, permanece igual, salvo el atributo type
, que en el caso de <textarea/>
es implícito.
Miremos cómo añadir un campo textarea al componente que usamos en la parte I de este artículo usando lo que que acabamos de aprender:
import React from "react"
export default function Form() {
const [formData, setFormData] = React.useState(
{nombre: "", apellidos: "", comentarios: ""}
)
console.log(formData);
function handleChange(eventObject) {
const nombreInput = eventObject.target.name;
const valorInput = eventObject.target.value;
setFormData(estadoAnterior => {
return {
...estadoAnterior,
[nombreInput]: valorInput
}
})
}
return (
<form>
<input
type="text"
placeholder="Nombre"
onChange={handleChange}
name="nombre"
value={formData.nombre}
/>
<input
type="text"
placeholder="Apellidos"
onChange={handleChange}
name="apellidos"
value={formData.apellidos}
/>
<textarea
placeholder="Comentarios"
onChange={handleChange}
name="comentarios"
value={formData.comentarios}
/>
</form>
)
}
checkbox
Los checkbox son fundamentalmente diferentes de los demás elementos input de tipo texto con los que hemos estado trabajando hasta ahora, dado que solo almacenan valores booleanos, por lo que no habrá una propiedad value
como en los demás inputs. En vez de ello, para controlar el valor del checkbox, se accede a la propiedad "checked", que será true
o false
dependiendo de si el usuario ha marcado el checkbox o no.
Dado que los checkbox almacenan valores booleanos, vamos añadir a nuestro objeto de estado un campo correspondiente
import React from "react"
export default function Form() {
const [formData, setFormData] = React.useState(
{
nombre: "",
apellidos: "",
email: "",
comentarios: "",
estaMarcadoTerminos: true
}
)
console.log(formData);
function handleChange(event) {
const {name,value,type,checked} = event.target;
setFormData(prevFormData => {
return {
...prevFormData,
[name]: type === "checkbox" ? checked : value
}
})
}
return (
<form>
<input
type="text"
placeholder="Nombre"
onChange={handleChange}
name="nombre"
value={formData.nombre}
/>
<input
type="text"
placeholder="apellidos"
onChange={handleChange}
name="apellidos"
value={formData.apellidos}
/>
<textarea
value={formData.comentarios}
placeholder="comentarios"
onChange={handleChange}
name="comentarios"
/>
<input
type="checkbox"
id="esMarcado"
checked={formData.marcado}
onChange={handleChange}
name="estaMarcadoTerminos"
/>
<label htmlFor="esMarcado">Aceptar terminos y condiciones</label>
<br />
</form>
)
}
En nuestra función handleChange
a la hora de asignar un valor a nuestra propiedad basada en eventObject.target.name
, hacemos referencia aeventObject.target.value
, pero con los checkbox no usamos esta propiedad para modificarlo, por lo que podemos usar un operador ternário y verificar si el tipo del input sobre el que se ha producido el evento es de tipo checkbox o no.
Para hacerlo, a la hora de recibir el objeto de evento hemos desestructurado algunas de sus propiedades como name,value,type y checked y luego a la hora de asignar un valor a la propiedad correspondiente, preguntamos si es de tipo checkbox, si lo es,se le asigna el valor de la propiedad checked
en caso contrario se le asigna value
.
radio buttons
En React, los radio buttons son una combinación de checkbox e inputs de tipo texto.
Analicemos este ejemplo:
import React from "react"
export default function Form() {
const [formData, setFormData] = React.useState(
{
nombre: "",
apellidos: "",
email: "",
comentarios: "",
estaMarcadoTerminos: true
}
)
console.log(formData);
function handleChange(event) {
const {name,value,type,checked} = event.target;
setFormData(prevFormData => {
return {
...prevFormData,
[name]: type === "checkbox" ? checked : value
}
})
}
return (
<form>
<input
type="text"
placeholder="Nombre"
onChange={handleChange}
name="nombre"
value={formData.nombre}
/>
<input
type="text"
placeholder="apellidos"
onChange={handleChange}
name="apellidos"
value={formData.apellidos}
/>
<textarea
value={formData.comentarios}
placeholder="comentarios"
onChange={handleChange}
name="comentarios"
/>
<input
type="checkbox"
id="esMarcado"
checked={formData.marcado}
onChange={handleChange}
name="estaMarcadoTerminos"
/>
<label htmlFor="esMarcado">Aceptar terminos y condiciones</label>
<br />
<br/>
<fieldset>
<legend>Ocupación</legend>
<input
type="radio"
id="radio1"
name="ocupacion"
value="Desempleado"
checked={formData.ocupacion === "Desempleado"}
onChange={handleChange}
/>
<label htmlFor="radio1"> Desempleado </label>
<br/>
<input
type="radio"
id="radio2"
name="ocupacion"
value="Media jornada"
checked={formData.ocupacion === "Media jornada"}
onChange={handleChange}
/>
<label htmlFor="radio2"> Media jornada </label>
<br/>
<input
type="radio"
id="radio3"
name="ocupacion"
value="Jornada completa"
checked={formData.ocupacion === "Jornada completa"}
onChange={handleChange}
/>
<label htmlFor="radio3"> Jornada completa </label>
</fieldset>
</form>
)
}
En este ejemplo, he añadido un fieldset
el cual contiene 3 radio buttons, cada radio button tiene una etiqueta label, las vinculo con el radio button a traves del atributo htmlFor
.
Además, a cada radio button le añado un atributo name
ya que en handleChange
usamos esta propiedad del objeto de evento para determinar qué propiedad de nuestro objeto de estado debe modificarse. Le ponemos el mismo nombre para que sólo uno de ellos pueda ser seleccionado por vez, además los 3 modifican la misma propiedad de nuestro estado.
Adicionalmente,le asignamos un value
por lo cual estaremos escuchando a cambios en los inputs, y esto ocurra, cogerá el valor de este input específico y lo asignará como el valor de la propiedad ocupacion
de nuestro estado.
A la hora de hacerlo un componente controlado, los radio buttons funcionan diferente,dado que necesitamos dotarle de un valor como hemos visto 2 líneas más arriba.
Dado que los radio buttons son como un híbrido entre checkbox y input type text, también podemos usar su propiedad checked para determinar si está marcado o no.
Como hemos visto en el código checked={formData.ocupacion === "desempleado"}
,checked={formData.ocupacion === "Media jornada"}
y checked={formData.ocupacion === "Jonada completa"}
, esto hace que ahora el valor sea controlado por el estado.
La expresión retornará true
y estará marcado el radio button sólo si hemos hecho clic en él y se ha modificado el valor de la propiedad ocupacion
a una de las tres opciones ("Desempleado","Media jornada" o "Jornada completa"). En caso contrario retornará false y checked estará desmarcado.
select
En HTML,para acceder al valor de una opción que ha sido seleccionada, debemos acceder a su propiedad selected
, en cambio en React añadimos una propiedad value
a la etiqueta <select>
, por lo que podemos transformala en una input controlado.
import React from "react"
export default function Form() {
const [formData, setFormData] = React.useState(
{
nombre: "",
apellidos: "",
email: "",
comentarios: "",
estaMarcadoTerminos: true,
colorFavorito:""
}
)
console.log(formData);
function handleChange(event) {
const { name, value, type, checked } = event.target;
setFormData(prevFormData => {
return {
...prevFormData,
[name]: type === "checkbox" ? checked : value
}
})
}
return (
<form>
<input
type="text"
placeholder="Nombre"
onChange={handleChange}
name="nombre"
value={formData.nombre}
/>
<input
type="text"
placeholder="apellidos"
onChange={handleChange}
name="apellidos"
value={formData.apellidos}
/>
<textarea
value={formData.comentarios}
placeholder="comentarios"
onChange={handleChange}
name="comentarios"
/>
<input
type="checkbox"
id="esMarcado"
checked={formData.marcado}
onChange={handleChange}
name="estaMarcadoTerminos"
/>
<label htmlFor="esMarcado">Aceptar terminos y condiciones</label>
<br />
<br />
<fieldset>
<legend>Ocupación</legend>
<input
type="radio"
id="radio1"
name="ocupacion"
value="Desempleado"
checked={formData.ocupacion === "Desempleado"}
onChange={handleChange}
/>
<label htmlFor="radio1"> Desempleado </label>
<br />
<input
type="radio"
id="radio2"
name="ocupacion"
value="Media jornada"
checked={formData.ocupacion === "Media jornada"}
onChange={handleChange}
/>
<label htmlFor="radio2"> Media jornada </label>
<br />
<input
type="radio"
id="radio3"
name="ocupacion"
value="Jornada completa"
checked={formData.ocupacion === "Jornada completa"}
onChange={handleChange}
/>
<label htmlFor="radio3"> Jornada completa </label>
</fieldset>
<br />
<label htmlFor="favColor">¿Cuál es tu color favorito?</label>
<br />
<select
id="favColor"
value={formData.colorFavorito}
onChange={handleChange}
name="colorFavorito"
>
<option value="">-- Elige una opción --</option>
<option value="rojo">Rojo</option>
<option value="naranja">Naranja</option>
<option value="amarillo">Amarillo</option>
</select>
</form>
)
}
Aqui podemos seguir usando nuestro manejador de eventos handleChange
por lo que también podemos añadirle una propiedad name
(de igual nombre a nuestra nueva propiedad en el objeto de estado).
La única observación que haría aquí es que en un principio inicializamos la propiedad colorFavorito con un string vacío, por lo que añadimos una option
que por defecto tenga el valor de un string vacío. Yo he decidido colocarla como una "título" (-- Elige una opción --)