skip to Main Content

I am trying to add values to a useState hook as a checkbox is clicked and remove that value when unchecked. I can add the values just fine but I can’t seem to figure out how to remove them. I can get this process to work for the price useState which is a float, but doing this action on a string is where I run into issues.

Here is the code section:

const [price, setPrice] = useState(0.00);
const [specOrder, setSpecOrder] = useState("");

const [specBurgers, setSpecBurgers] = useState([]);
useEffect( () => {
    axios.get('http://localhost:8800/specialtyburgers')
    .then(res => {
        setSpecBurgers(res.data);
    })
}, [])

function handleSpec(p, e) {
    var temp = parseFloat(p);
    if(e.target.checked) {
        setSpecOrder(prevSpecOrder => prevSpecOrder + e.target.value);
        setPrice(prevPrice => prevPrice + temp);
    }
    else if(!e.target.unchecked){
        setSpecOrder(prevSpecOrder => prevSpecOrder);
        setPrice(prevPrice => prevPrice - temp);
    }
}
var specBurgerDetails = "";
specBurgerDetails = specBurgers.map( (item, index) => {
    return(
        <div className="item">
            <h2 key={index} className='itemName'>{item.SpecBurgerType}</h2>
            <p>{item.Protein}</p>
            <p>{item.Toppings}</p>
            <p>{item.Price}</p>
            <input type='checkbox' value={item.SpecBurgerType} onChange={(e) => handleSpec(item.Price, e)}/>
            <p>{specOrder}</p>
            <p>{price}</p>
        </div>
    )
});

3

Answers


  1. I’d suggest making the state of the checkbox part of your state and making the total price a calculated value rather than a value stored in state.

    I don’t know what "spec order" is supposed to be in your code and there isn’t enough detail to show doing the above in the context of your code, but here’s an example of having a price and, separately, an extra amount that is conditionally included in the total:

    const { useState } = React;
    
    const Example = () => {
        const [price, setPrice] = useState(100);
        const [extra, setExtra] = useState(10);
        const [useExtra, setUseExtra] = useState(false);
        const totalPrice = price + (useExtra ? extra : 0);
        //    ^^ Notice how `totalPrice` is a computed value
        
        return (
            <div>
                <div>
                    <label>
                        Price:{" "}
                        <input
                            type="number"
                            value={price}
                            onChange={({ currentTarget: { valueAsNumber } }) => setPrice(valueAsNumber)}
                        />
                    </label>
                </div>
                <div>
                    <label>
                        <input
                            type="checkbox"
                            checked={useExtra}
                            onChange={({ currentTarget: { checked } }) => setUseExtra(checked)}
                        />{" "}
                        Use extra
                    </label>
                </div>
                <div>
                    <label>
                        Extra:{" "}
                        <input
                            type="number"
                            value={extra}
                            disabled={!useExtra}
                            onChange={({ currentTarget: { valueAsNumber } }) => setExtra(valueAsNumber)}
                        />
                        <div></div>
                    </label>
                </div>
                <div>
                    <strong>Total:</strong> {totalPrice}
                </div>
            </div>
        );
    };
    
    const root = ReactDOM.createRoot(document.getElementById("root"));
    root.render(<Example />);
    <div id="root"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
    Login or Signup to reply.
  2. It might make more sense to calculate your specOrder variable and price on each render, rather than storing them in state. See the below example – the only state you need to store is the checkbox state, and then you can build the value you need. Trying to keep it in sync will invariably lead to headaches. See the example below: it’s a bit contrived and you could abstract some of it into reusable hooks/components but it illustrates the point.

    If you still want to use state, you can copy use the usePrevious hook that’s available in other codebases. EG: https://github.com/streamich/react-use/blob/master/src/usePrevious.ts

     const {useState} = React;
    
    const MyComponent = () => {
      // Set up our internal state 
      const [hasApple, setHasApple] = useState(false);
      const handleAppleChange = () => setHasApple(!hasApple);
      
      const [hasPear, setHasPear] = useState(false);
      const handlePearChange = () => setHasPear(!hasPear);
    
      // Calculate our "state" from what we selected, rather than trying to build it in sync
      let price = 0;
      let items = [];
      if (hasApple) {
          price += 9.0;
          items.push("Apple");
      }
      if (hasPear) {
          price += 10.0;
          items.push("Pear");
      }
    
      const itemsAsString = items.length > 0 ? items.join(", ") : "No items";
    
      return (
          <div>
              <h1>My Cool Shop</h1>
              <p>Select some items</p>
              <div>Apple: <input type="checkbox" name="apple" checked={hasApple} onChange={handleAppleChange} /></div>
              <div>Pear: <input type="checkbox" name="pear" checked={hasPear} onChange={handlePearChange} /></div>
              <div>Price: {price}</div>
              <div>Selected items: {itemsAsString}</div>
          </div>
      );
    }
    
    const container = document.getElementById('root');
      
    ReactDOM.render(<MyComponent />, container);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
    <div id="root"></div>
    Login or Signup to reply.
  3. The event triggered when checking contains the value of the element that is being checked or unchecked. Just add it and subtract when necessary to the previous state that you have. The which in this case for example I am getting from the setState’s callback function. It’s also good to know that the event returns a string, so we just turn it into a number with Number()

      const handleChange = (e) => {
        if(e.target.checked){
          setPrice((prevPrice)=> prevPrice + Number(e.target.value))
        }else{
          setPrice((prevPrice)=> prevPrice - Number(e.target.value))
        }
      }
    
      return(
        <input type="checkbox" value={20} onChange={handleChange}/>
      )
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search