norrisollie
norrisollie

Reputation: 331

How to update a specific value in state object using hooks?

I'm trying to update the quantity of an item in a shopping basket, however struggling to get it working?

I have an input field that lets the user update the quantity, the quantity is used to update the total price of items based on the number, as well as also the total basket cost.

I have managed to get the correct item in the array of objects that make up the basket, however i can't seem to be able to update the quantity using the state hook, how would i be able to do this?

My idea is to update it in the if statement, then replace the old object with the new object with the updated quantity... but my knowledge on how to do this is non existent...

this is what i have so far....

    const [basketData, setBasketData] = useState(null);

    useEffect(() => {
        setBasketData(basket);
    }, []);

    const quantityHandler = (e) => {
        basketData.forEach((basket) => {
            if (Object.values(basket).includes(e.target.name)) {
            }
        });
    };

this is the data used for the basket:

export const basket = [
    {
        productID: 1,
        productName: "Mountain Dew",
        isAgeRestricted: false,
        productDescription: "Carbonated citrus flavoured soft drink",
        unitPrice: 1.8,
        quantity: 2,
    },
    {
        productID: 2,
        productName: "Desperados",
        isAgeRestricted: true,
        productDescription: "Beer with flavourings and Tequila",
        unitPrice: 2.6,
        quantity: 6,
    },
    {
        productID: 3,
        productName: "Jack Daniels",
        isAgeRestricted: true,
        productDescription:
            "A perfect mix of Jack Daniel's Old No. 7 Tennessee Whiskey & cola",
        unitPrice: 3.35,
        quantity: 4,
    },
];

Upvotes: 1

Views: 854

Answers (2)

Luke
Luke

Reputation: 2911

Here's a complete solution (also available at https://stackblitz.com/edit/react-basket55?file=src/App.js ):

import React, { useState, useEffect } from "react";
import "./style.css";

export default function App() {
  const basket = [
    {
      productID: 1,
      productName: "Dew",
      quantity: 1
    },
    {
      productID: 2,
      productName: "Bud",
      quantity: 1
    },
    {
      productID: 3,
      productName: "Jack",
      quantity: 1
    }
  ];

  const [basketData, setBasketData] = useState(basket);

  function handleInputChange(e) {
    let newDataArray = basketData.map(basketItem => {
      if (basketItem.productName == e.target.form.itemName.value) {
        let x = e.target.form.itemQuantity.value
          ? e.target.form.itemQuantity.value
          : 1;
        basketItem.quantity = x;
      }
      return basketItem;
    });
    setBasketData([...newDataArray]);
    
  }

  return (
    <div>
      <h1>Basket Example</h1>
      <form>
        <label>
          Item:
          <select name="itemName" onChange={handleInputChange}>
            {basket.map(function(data, index) {
              return (
                <option key={index} value={data.productName}>
                  {data.productName}
                </option>
              );
            })}
          </select>
        </label>
        <br />
        <label>
          Item Quantity:
          <input
            name="itemQuantity"
            type="Number"
            onChange={handleInputChange}
          />
        </label>
      </form>
      {basketData.map(i => {
        return (
          <p key={i.productName} >
            Item: {i.productName} {i.quantity}
          </p>
        );
      })}
    </div>
  );
}

Upvotes: 0

Pauline
Pauline

Reputation: 151

Do you use the quantityHandler onClick? Something like this:

const quantityHandler = (e) => {
  let newDataArray = basketData.map((basket) => {
      if (basket.includes(e.target.name)) {
         return {...basket, quantity: e.target.value}
      }
      return basket;
  });
  setBasketData([...newDataArray])
};

As you doing more complex things you use map instead of forEach. And returning: {...basket, quantity: value} is gonna return the array + updated quantity on that object. If it's not includes the right name it just returns the item. Then set the old array to the updated one.

Instead of includes you could also do if(basket.name === e.target.name), it just seems more exact :)

Upvotes: 2

Related Questions