ismail pervez
ismail pervez

Reputation: 199

Getting multiple checkbox values from react not working

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

Answers (3)

Ammar
Ammar

Reputation: 272

There are multiple things that are not right in your code.

  1. setState is an async operation, which means the console.log("toppings: ", toppings) right after the setState will show you the stale state.
  2. In the next line you are pushing the toppings into the toppingsArray but the toppings contain the stale data.
  3. Next line you have 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).
  4. Also, while pushing the toppings into the array, you need to check if the toppings already exist or not.

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

Kirill Savik
Kirill Savik

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

Amit
Amit

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

Related Questions