Reputation: 199
I have a small react project which contains a form, I am trying to get multiple values from a checkbox, but everytime i click an item (checkbox) for the first time, it starts out as null, then when i click the another item, It stores the first Item. I would like to store multiple Items from a checkbox. Here is the code below.
import { useState } from "react";
const Toppings = () => {
const [toppings, setToppings] = useState(null)
const [toppingsArray, setToppingsArray] = useState([])
function handleCheck(event) {
if (event.target.checked) {
setToppings({
"type": event.target.id,
"price": event.target.value
})
console.log("toppings: ", toppings)
toppingsArray.push(toppings)
setToppingsArray([toppings])
console.log("toppings array: ", toppingsArray)
}
}
return (
<>
<h2>you can select multiple</h2>
<form>
<label htmlFor="pepperoni">
<input onChange={handleCheck} type="checkbox" name="pepperoni" id="pepperoni" value={300} />
pepperoni
</label>
<label htmlFor="cheese">
<input onChange={handleCheck} type="checkbox" name="cheese" id="cheese" value={200} />
cheese
</label>
<label htmlFor="onions">
<input onChange={handleCheck} type="checkbox" name="onions" id="onions" value={100} />
onions
</label>
</form>
<p>you have selected {JSON.stringify(toppings)}</p>
<p>you have {JSON.stringify(toppingsArray)}</p>
</>
)
}
export default Toppings[enter image description here][1];
Upvotes: 3
Views: 1555
Reputation: 272
There are multiple things that are not right in your code.
console.log("toppings: ", toppings)
right after the setState will show you the stale state.setToppingsArray([toppings])
, which is wrong as well because you have pushed the data into toppingsArray so you need to update the state by passing that array, like this setToppingsArray(toppingsArray)
.To solve all these problems you could do something like this inside your handleCheck function:
function handleCheck(event) {
const newToppings = {
type: event.target.id,
price: event.target.value,
};
if (event.target.checked) {
setToppings(newToppings);
toppingsArray.findIndex(top => top.type === newToppings.type) < 0 &&
setToppingsArray([...toppingsArray, newToppings]);
} else {
setToppingsArray(toppingsArray.filter(top => top.type !== newToppings.type));
}
}
Upvotes: 1
Reputation: 1278
Please use this code.
function handleCheck(event) {
const item = {
"type": event.target.id,
"price": event.target.value
};
if (event.target.checked) {
setToppings(item);
if(toppingsArray.map(val => val["type"]).indexOf(item["type"]) == -1) setToppingsArray([...toppingsArray, item]);
} else {
setToppingsArray(toppingsArray.filter(val => val["type"] != item["type"]));
}
}
Upvotes: 1
Reputation: 177
Get rid of the line that says toppingsArray.push(toppings) since the toppingsArray is in state so it is immutable
Add a line that change the setToppingsArray line to
setToppingsArray(toppingsArray=>[...toppingsArray, toppings])
The useState hook can be used as a function that has the first parameter give the initial state. Then we just take that state and spread into into an array and add the new thing
There is also no reason to store the initial toppings in state since it has no interaction with the dom. It can be a js const
You should also have a checked attribute on the checkboxes that checks if a topping in is the toppings array
Upvotes: 1