Articolo originale: React Tutorial – How to Work with Multiple Checkboxes
Gestire caselle a scelta multipla in React è completamente diverso da come usi normali caselle a scelta multipla in HTML.
Quindi in questo articolo vedremo come lavorare con varie caselle a scelta multipla in React.
Imparerai a:
- Come usare le caselle a scelta multipla come Input Controllati in React
- Come usare i metodi per array map e reduce per calcoli complessi
- Come creare un array di una specifica lunghezza preriempito con uno specifico valore
e molto altro.
Quindi, iniziamo.
Come lavorare con una singola casella
Iniziamo con la funzionalità di una singola casella prima di muoverci a multiple caselle a scelta multipla.
In questo articolo userò gli Hook di React per creare i componenti, se non sei familiare, puoi leggere questa guida per principianti sugli Hook di React.
Dai un'occhiata al codice qua sotto:
<div className="App">
Select your pizza topping:
<div className="topping">
<input type="checkbox" id="topping" name="topping" value="Paneer" />Paneer
</div>
</div>
Ecco una demo in Code Sandbox.
Nel codice qua sopra abbiamo dichiarato una singola casella in maniera simile a come si dichiara una casella a scelta multipla in HTML.
Quindi possiamo facilmente selezionare e deselezionare la casella come mostrato sotto:

Ma per mostrare sullo schermo se è selezionata o meno dobbiamo convertirla ad un Input Controllato.
In React un Input Controllato è gestito dallo stato, quindi il valore dell'input può essere cambiato solo cambiando lo stato legato a quell'input.
Dai un'occhiata al codice qua sotto:
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>
);
}
Ecco una demo in Code Sandbox.
Nel codice sopra, abbiamo dichiarato lo stato isChecked
nel componente con un valore iniziale di false
usando l'hook useState
:
const [isChecked, setIsChecked] = useState(false);
Poi abbiamo dato due proprietà in più alla casella a scelta multipla, checked
e onChange
, in questo modo:
<input
...
checked={isChecked}
onChange={handleOnChange}
/>
Ogni volta che clicchiamo la casella, la funzione handleOnChange
viene invocata ed usata per impostare il valore dello stato isChecked
.
const handleOnChange = () => {
setIsChecked(!isChecked);
};
Quindi se la casella è selezionata, impostiamo il valore di isChecked
a false
, se invece non è selezionata, impostiamo il valore a true
usando !isChecked
. Quindi poi passiamo il valore alla casella per la proprietà checked
.
In questo modo la casella input diventa un input controllato il cui valore è gestito dallo stato.
Nota che in React è sempre raccomandato usare Input Controllati per campi di input anche se il codice sembra complicato. Questo garantisce che l'input venga cambiato solo dentro onChange
.
Lo stato dell'input non verrà cambiato in nessun altro modo e otterrai sempre il valore corretto e aggiornato dello stato del tuo input.
Solo in certi casi puoi usare React ref per usare l'input in modo non controllato.
Come gestire caselle multiple
Ora, vediamo come gestire più caselle a scelta multipla.
Guarda questa demo su Code Sandbox.

Qui, stiamo mostrando una lista di aggiunte con il loro prezzo corrispondente e a seconda di quali sono selezionate dobbiamo mostrare il costo totale.
In precedenza, con una singola casella, avevamo solo lo stato isChecked
e cambiavamo lo stato della casella basato su quello.
Ma ora abbiamo svariate caselle, quindi non è pratico aggiungere multiple invocazioni a useState
per ogni casella.
Quindi dichiariamo un array nello stato che racchiude lo stato di ogni casella a scelta multipla.
Per creare un array di lunghezza uguale al numero di caselle, possiamo usare il metodo per array fill
in questo modo:
const [checkedState, setCheckedState] = useState(
new Array(toppings.length).fill(false)
);
Qui abbiamo dichiarato uno stato con un valore iniziare di un array riempito con il valore false
.
Quindi se abbiamo 5 aggiunte allora lo stato checkedState
conterrà cinque valori false
in questo modo:
[false, false, false, false, false]
E una volta che selezioniamo/deselezioniamo una casella cambieremo il corrispondente false
in true
.
Ecco una finale su Code Sandbox.
Il codice completo di App.js
è come questo:
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>
);
}
Capiamo cosa stiamo facendo qua.
Abbiamo dichiarato la singola casella a scelta multipla come mostrato sotto:
<input
type="checkbox"
id={`custom-checkbox-${index}`}
name={name}
value={name}
checked={checkedState[index]}
onChange={() => handleOnChange(index)}
/>
Qui, abbiamo aggiunto l'attributo checked
con il valore corrispondente di true
o false
dallo stato checkedState
in modo che ogni casella mostrerà correttamente se è selezionata o meno.
Abbiamo anche aggiunto la proprietà onChange
e passiamo come argomento l'index
della casella che è selezionata/deselezionata al metodo handleOnChange
.
Il metodo handleOnChange
appare così:
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);
};
Qui prima iteriamo sull'array checkedState
usando il metodo per array map
. Se il valore passato come parametro position
combacia con l'index
corrente, allora invertiamo il suo valore usando !item
(se è false
in true
, se è true
in false
).
Se il valore di index
non combacia con il parametro position
allora non cambiamo il valore, ma lo restituiamo così com'è.
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;
}
});
Ho usato l'operatore ternario ?:
perché rende il codice più compatto, ma puoi usare qualsiasi metodo per array.
Se non hai familiarità con come funzionano metodi per array quali map
o reduce
, allora guarda questo articolo che ho scritto.
Successivamente, stiamo impostando l'array checkedState
all'array updatedCheckedState
, questo è importante perché se non cambi checkedState
dentro handleOnChange
allora non puoi selezionare/deselezionare le caselle.
Questo è perché stiamo usando il valore di checkedState
per la casella per determinare se la casella è selezionata o meno (visto che è un input controllato come mostrato sotto):
<input
type="checkbox"
...
checked={checkedState[index]}
onChange={() => handleOnChange(index)}
/>
Nota che abbiamo creato una variabile updatedCheckedState
separata e stiamo passando questa variabile alla funzione setCheckedState
e stiamo usando il metodo reduce
su updatedCheckedState
e non sull'array checkedState
originale.
Questo è perché, di default, la funzione setCheckedState
usata per aggiornare lo stato è asincrona.
Non c'è garanzia che solo perché hai invocato la funzione setCheckedState
allora ottieni il valore aggiornato di checkedState
sulla riga successiva.
Quindi abbiamo creato una variabile separata e usato il metodo reduce
su quella.
Puoi leggere questo articolo se non hai familiarità su come funziona lo stato in React.
Quindi per calcolare il prezzo totale stiamo usando il metodo reduce
:
const totalPrice = updatedCheckedState.reduce(
(sum, currentState, index) => {
if (currentState === true) {
return sum + toppings[index].price;
}
return sum;
},
0
);
La callback di reduce
riceve quattro parametri, di cui ne stiamo usando solo tre: sum
, currentState
e index
. Puoi usare nomi diversi se vuoi visto che sono solo parametri.
Stiamo anche passando 0
come valore iniziale del parametro sum
.
Quindi dentro la funzione stiamo controllando se il valore corrente dell'array checkedState
è true
o meno.
Se è true
, questo significa che la casella è selezionata e quindi stiamo aggiungendo il valore corrispondente del prezzo con sum + toppings[index].price
.
Se il valore dell'array checkedState
è false
allora non aggiungiamo il prezzo, ma restituiamo il valore calcolato precedentemente di sum
.
Quindi stiamo dando il valore di totalPrice
allo stato total
usando setTotal(totalPrice)
.
In questo modo possiamo calcolare correttamente il valore totale delle aggiunte selezionate come puoi vedere sotto.

Ecco un Preview link della demo su Sandbox per provarlo tu stesso.