Trabajar con múltiples casillas en React es completamente diferente a cómo se usan las casillas de verificación en HTML.
Por lo que en este artículo, vamos a ver cómo hacerlo en React.
Aprenderás a:
- Cómo usar una casilla de verificación como Input Controlado en React,
- Cómo usar los métodos de arreglo "map" y "reduce" para cálculos complejos,
- Cómo crear un arreglo de un largo específico y con valores pre cargados,
y mucho más.
Este artículo es parte de mi curso Mastering Redux. Aquí tienes un adelanto de la aplicación que vamos a crear en el curso.
Así que empecemos.
Cómo trabajar con una sola casilla de verificación
Antes de aprender a trabajar con varias casillas, empezaremos programando solo uno.
En este artículo, para crear componentes voy a estar usando la sintaxis de React Hooks. Si no estás familiarizado con esta sintaxis, puedes darle un vistazo a mi artículo [en inglés] Introduction to React Hooks.
Mira el siguiente código:
<div className="App">
Select your pizza topping:
<div className="topping">
<input type="checkbox" id="topping" name="topping" value="Paneer" />Paneer
</div>
</div>
Aquí tienes la demo.
En el código de arriba, declaramos una única casilla.
Como se muestra abajo, podemos seleccionar y de seleccionarlo de manera muy fácil:

Pero para mostrar en pantalla si está seleccionado o no, tenemos que convertirlo a un Input Controlado.
En React, los Inputs Controlados se manejan mediante el estado, por lo que solamente podemos cambiar el valor del input cambiando su estado.
Mira el siguiente código:
export default function App() {
const [isChecked, setIsChecked] = useState(false);
const handleOnChange = () => {
setIsChecked(!isChecked);
};
return (
<div className="App">
Select your pizza topping:
<div className="topping">
<input
type="checkbox"
id="topping"
name="topping"
value="Paneer"
checked={isChecked}
onChange={handleOnChange}
/>
Paneer
</div>
<div className="result">
Above checkbox is {isChecked ? "checked" : "un-checked"}.
</div>
</div>
);
}
y aquí tienes la demo
En el código de arriba, con el hook useState
declaramos el estado isChecked
del componente, con el valor inicial false
:
const [isChecked, setIsChecked] = useState(false);
Después, a la casilla de verificación le damos dos props adicionales, checked
y onChange
, de la siguiente manera:
<input
...
checked={isChecked}
onChange={handleOnChange}
/>
Cuando hagamos clic en la casilla de verificación, la función handleOnChange
será la encargada de cambiar el valor del estado isChecked
const handleOnChange = () => {
setIsChecked(!isChecked);
};
Entonces, si la casilla está seleccionado, el valor de isChecked
es false
. Pero si no lo está, el valor estrue
al usar !isChecked
.
De esta manea la casilla se convierte en un input controlado, cuyo valor es manejado mediante el estado del componente.
Hay que tener en cuenta que en React siempre se recomienda usar inputs controlados para los campos de inputs, aun si el código luce complicado. Esto garantiza que el cambio del input solo ocurra dentro de la función onChange
.
El estado de un input no podrá ser cambiado de otra forma y así siempre tendrás el valor correcto y actual del estado del input.
Solo en raras ocasiones se puede usar React ref para poder manejar el input de manera no controlada.
Cómo manipular múltiples casillas de verificación
Veamos ahora como trabajar con varias casillas.
Mira esta demo

Aquí estamos mostrando una lista de aderezos y sus precios. Dependiendo cuantos aderezos sean seleccionados, necesitamos mostrar el monto total.
Antes, cuando teníamos un solo casilla de verificación, solo teníamos el estado isChecked
para cambiar el estado de la casilla de verificación.
Pero ahora, como tenemos varias casillas de verificación, no es práctico hacer varios llamados useState
para cada uno.
Entonces, declaremos un arreglo dentro del estado e indiquemos el estado de cada una de las casillas de verificación.
Para crear un arreglo cuyo largo sea igual número de casillas de verificación, Podemos usar el método de arreglo fill
de este método:
const [checkedState, setCheckedState] = useState(
new Array(toppings.length).fill(false)
);
Aquí hemos declarado un estado con un valor inicial como un arreglo relleno con el valor false
.
Entonces, si témenos cinco coberturas, el arreglo de estado checkedState
tendrá cinco valores false
:
[false, false, false, false, false]
Y una vez que marquemos / desmarquemos la casilla, cambiaremos el false
correspondiente a true
y viceversa.
Aquí está la demo final.
Y el código completo de App.js
luce de esta manera:
import { useState } from "react";
import { toppings } from "./utils/toppings";
import "./styles.css";
const getFormattedPrice = (price) => `$${price.toFixed(2)}`;
export default function App() {
const [checkedState, setCheckedState] = useState(
new Array(toppings.length).fill(false)
);
const [total, setTotal] = useState(0);
const handleOnChange = (position) => {
const updatedCheckedState = checkedState.map((item, index) =>
index === position ? !item : item
);
setCheckedState(updatedCheckedState);
const totalPrice = updatedCheckedState.reduce(
(sum, currentState, index) => {
if (currentState === true) {
return sum + toppings[index].price;
}
return sum;
},
0
);
setTotal(totalPrice);
};
return (
<div className="App">
<h3>Select Toppings</h3>
<ul className="toppings-list">
{toppings.map(({ name, price }, index) => {
return (
<li key={index}>
<div className="toppings-list-item">
<div className="left-section">
<input
type="checkbox"
id={`custom-checkbox-${index}`}
name={name}
value={name}
checked={checkedState[index]}
onChange={() => handleOnChange(index)}
/>
<label htmlFor={`custom-checkbox-${index}`}>{name}</label>
</div>
<div className="right-section">{getFormattedPrice(price)}</div>
</div>
</li>
);
})}
<li>
<div className="toppings-list-item">
<div className="left-section">Total:</div>
<div className="right-section">{getFormattedPrice(total)}</div>
</div>
</li>
</ul>
</div>
);
}
Veamos que estamos haciendo aquí.
Como se muestra aquí abajo, hemos declarado la casilla de verificación de entrada como se muestra a continuación:
<input
type="checkbox"
id={`custom-checkbox-${index}`}
name={name}
value={name}
checked={checkedState[index]}
onChange={() => handleOnChange(index)}
/>
Aquí, agregamos el atributo checked
con el valor del estado checkedState
, true
o false
, según corresponda.
También añadimos un manejador onChange
y le pasamos el index
de la casilla que está marcada/desmarcada al método handleOnChange
.
El método manejador handleOnChange
debe verse así:
const handleOnChange = (position) => {
const updatedCheckedState = checkedState.map((item, index) =>
index === position ? !item : item
);
setCheckedState(updatedCheckedState);
const totalPrice = updatedCheckedState.reduce(
(sum, currentState, index) => {
if (currentState === true) {
return sum + toppings[index].price;
}
return sum;
},
0
);
setTotal(totalPrice);
};
Aquí, primero recorremos el array checkedState
utilizando el método arreglo map
. Si el valor del parámetro position
pasado coincide con el index
actual, entonces invertimos su valor. Entonces, si el valor es true
se convertirá en false
usando !item
y si el valor es false
, entonces se convertirá en true
Si el index
no coincide con el parámetro position
proporcionado, entonces no estamos invirtiendo su valor, sino que simplemente devolvemos el valor tal cual.
const updatedCheckedState = checkedState.map((item, index) =>
index === position ? !item : item
);
// the above code is the same as the below code
const updatedCheckedState = checkedState.map((item, index) => {
if (index === position) {
return !item;
} else {
return item;
}
});
He utilizado el operador ternario ?:
porque hace el código más corto, pero puedes utilizar cualquier método de arreglo.
Si no estás familiarizado como funcionan los métodos map
oreduce
, puedes echarle un vistazo a este artículo que escribí.
Luego, establecemos el arreglo checkedState
en el arreglo updatedCheckedState
. Esto es importante porque si no actualizamos el estado checkedState
dentro del manejador handleOnChange
, entonces no podrás marcar/desmarcar la casilla de verificación.
Esto es porque estamos usando el valor de checkedState
de la casilla para determinar si este está o no marcada (ya que es una entrada controlada como se muestra abajo):
<input
type="checkbox"
...
checked={checkedState[index]}
onChange={() => handleOnChange(index)}
/>
Ten en cuenta que creamos una variable updatedCheckedState
separada, y a su vez, esta se la pasamos a la función updatedCheckedState
y no al arreglo original checkedState
.
Esto es porque, por default, la función setCheckedState
usada para actualizar el estado es asincrónica.
Llamar a la función setCheckedState
no garantiza que obtendrás el valor actualizado del arreglo checkedState
en la siguiente línea.
Por lo que creamos una variable separada y usamos esa en el método reduce
.
Entonces, para calcular el precio total, usamos el método de arreglo reduce
:
const totalPrice = updatedCheckedState.reduce(
(sum, currentState, index) => {
if (currentState === true) {
return sum + toppings[index].price;
}
return sum;
},
0
);
El método de arreglo reduce
recibe cuatro parámetros, de los cuales usaremos solamente tres: sum
, currentState
e index
. Puedes usar nombres distintos, ya que son solo parámetros.
También estamos pasando el valor 0
como valor inicial, que también se lo conoce como el valor accumulator
del parámetro sum
.
Luego, dentro de la función reduce, chequeamos si el valor actual del array checkedState
es true
o no.
Si lo es true
, esto significa que la casilla está marcada, por lo que añadiremos el valor correspondiente de price
correspondiente utilizando sum + toppings[index].price
Si el valor del arreglo checkedState
es false
, entonces no estamos añadiendo su precio, sino que solo estamos devolviendo el valor anterior calculado de sum
.
Luego, vamos a establecer que el valor totalPrice
al estado total
utilizando setTotal(totalPrice)
De esta forma, podemos calcular correctamente el precio total de los aderezos seleccionados como pueden ver debajo:

Aquí tiene el link de la demo de arriba, así pueden probarla ustedes mismos.
¡Gracias por leer!
A muchos desarrolladores se les dificulta entender como funciona Redux, pero todo desarrollador especializado en React debe saber como trabajar con Redux, ya que muchos proyectos dentro de la industria usa Redux para gestionar proyectos de gran escala.
Para hacerlo fácil para ti, he creado el curso Mastering Redux.
En este curso, aprenderás Redux desde cero y también crearás un aplicación de pedido de comida, desde el inicio y con Redux.
Dale clic a la imagen de abajo para unirte al curso y obtener un descuento especial por tiempo limitado, además de también obtener mi libro más popular "Mastering Modern JavaScript", gratis.

Si quieres mantenerte actualizado con contenidos sobre JavaScript, React y Node.js, sigueme en LinkedIn.