reactjsreact-state

useState getting all item property totals


I'm storing an array of products added to a cart in a useState, each cart product has a quantity that can increase and decrease which all works fine.

I then wanted to display the total number of all the product quantities in the basket. Basically (Product 1 has a quantity of 2) + (Product 1 has a quantity of 3) = Total quantity of 5.

I thought I had the answer with the below code:

const [cartQuantity, setCartQuantity] = useState(0)

const updateCartTotals = () => {
  let TotalQuantity = 1;
  cartProducts.map(({productQuantity}) => TotalQuantity = TotalQuantity + productQuantity)
  setCartQuantity(TotalQuantity)
}

and when I run this function after each add to cart function I created has ran it does actually update the carts total quantity of products to the correct number matching the number of products added to the cart:

3 products

It also updates fine if I increase the number of quantity per item:

6 products

However if I reduce a quantity it still increases by 1 (should be 5 total but showing 7)

5 products

then if I reduce another one the total quantity does reduce but it's now one behind where it should be at that point, and I'm not sure why.

I know I'm building something I haven't before and working with React that I'm just getting used too, but I keep feeling rather silly because I get close to an answer to a problem but then I keep finding there's an issue I can't get my head around. So any help would be much appreciated.

Thanks


Solution

  • This should not be a separate state, since you can calculate it directly from the other states. That will make it impossible for them to get out of sync.

    //const [cartQuantity, setCartQuantity] = useState(0)
    let cartQuantity = 0;
    cartProducts.forEach(({ productQuantity }) => cartQuantity = cartQuantity + productQuantity);
    

    If you're concerned that this calculation is expensive (i for one am not concerned), you can wrap it in a useMemo so that it will only be recomputed when cartProducts change.

    const cartQuantity = useMemo(() => {
      let sum = 0;
      cartProducts.forEach(({ productQuantity }) => sum = sum + productQuantity);
      return sum;
    }, [cartProducts])