Summing up prices of user's cart from 2 arrays

Viewed 281

So, I have two arrays, one called incart and the other called products

The incart array contains objects (representing an item they have in the cart). Each object is composed of a product id and a product qty.

Moreover, the products array contains all the products on the website. For example, inside the products array there are objects of each item. It contains a bunch of info about the product. The important one here is the product price.

In short, I need to sum up all the prices. The complicated thing is matching the individual product qty with the product price which are found in two arrays.

So my set up is as follows: The products array represents all the items that the user has in their cart, which is being set by filtering through the incart array, this is being done to obtain the price of each product.

const {incart} = useContext(ContextApp)
const [products, setProducts] = useState([])

useEffect(()=> {

db.collection('products').doc('products').onSnapshot(snap=> {
  const productsdata = snap.data().products
  setProducts(productsdata.filter(x=> incart.some(el=> x.id === el.id)))
})
},[incart])

Any idea how I can relate these two arrays, maybe to compress them into another array which would in short only contain the price of the item and the qty of the item.

2 Answers

const incart = [{id: 1, qty: 1}, {id: 2, qty: 10}]
const products = [
  {id: 1, price: 1},
  {id: 2, price: 10}
]

const total = incart.reduce((acc, {id, qty}) => 
  acc + qty * products.find(x => x.id === id).price, 0)
console.log(total)

You're using the list of products as a lookup table, so I would use a Map instead of an array.

You also don't necessarily need to refetch all products from Firebase whenever the list of items in the cart changes, so I would store the product map in state, then calculate the total price in the body of the component.

As an aside, the onSnapshot method subscribes to changes in the document, so you either need to use get() instead, or you need to unsubscribe when the component unmounts. You can do this by returning the unsubscribe function from the body of the effect.

function MyComponent() {
  const { incart } = useContext(ContextApp);
  const [products, setProducts] = useState(null);

  useEffect(() => {
    const unsubscribe = db.collection("products")
      .doc("products")
      .onSnapshot((snap) => {
        const productsdata = snap.data().products;
        setProducts(
            new Map(productsdata.map(p => [p.id, p]))
        );
      });
    return unsubscribe;
  }, []);

  const prices = products != null
    ? incart.map(p => products.get(p.id).price)
    : [];

  const totalPrice = prices.reduce((total, p) => total + p, 0);

  // ...
}

Related