'I have an <Add /> component that is called in two different pages, but only one of them is receiving the add count prop passed to it in React JS

Please help me understand why this logic is not working on one of the instances of my counter button. My goal is to have my counter display the count like this:

sample counter

To add items to the cart, I am using this function:

 const handleAddProduct = (product) => {
    const productExists = cartItems.find((item) => item._id === product._id);

    if (productExists) {
      setCartItems(
        cartItems.map((item) =>
          item._id === product._id
            ? {
                ...productExists,
                customer_qty: productExists.customer_qty + 1,
              }
            : item
        )
      );
     
    } else {
      setCartItems([...cartItems, { ...product, customer_qty: 1 }]);
    }
  };

This works well when I view the <Cart /> page because this page displays products in the "cartItems" array that have the newly added "customer_qty" key. The <Add /> component is rendering

<p> product.customer_qty </p>

The cartItems and the handleAddProduct are passed down like this:

- \<App />  
   - \<Cart />  
        - \<ShoppingCartCard /> /*Each card here is an item from "cartItems"*/ 
            - \<Add />  

However, in the normal shopping page, I cannot get the same

product.customer_qty

to display on the counter, since the product card instance is rendered for each item in the original array of products, so those products don't have "product.customer_qty"

For the other branch of the site, the cartItems and the handleAddProduct are passed down like this:

- \<App />  
   - \<Products />  
        - \<Specials /> /*Specials passes down product data */
            - \<Carousel />  
                - \<ProductCard />  
                    - \<Add />

So what I am missing is a way to have the <Add /> components in both branches, to display the same count number.

I have tried doing a setCount, but if I do it at the top <App /> level, it doesn't count individually for each product (all products get the same count). If I do it at the product card level, then then it is two different counts.

what am I missing here? The count should appear in three places: The shopping cart in the masthead, the Cart page, and at each product card.

I can share my Github repository if you'd like to see it (It's private because this is a course assignment.).



Solution 1:[1]

OK, so I realise that I have probably over-complicated my question. But the difficulty lies in the complex way in which data for each product is received and displayed. I have solved my problem simply by understanding the difference between what "product" means in each component (Cart and ProductCard).

in the <Cart /> component, each "product" is a synthetic duplicate of the original (created by using the spread operator "...". And is one object of a small array of products that have been added to "CartItems".

Whereas in the <ProductCard /> component, each "product" an object from a large array from the original dataset .

Originally I wanted my <Add /> component to display the value for the key "customer_qty:" which would have been counting how many items the customer wants to purchase. This displayed well in the <Cart /> component, but not in the <Products /> component.

Remember: While the <Cart /> lists items in that have already been added to the shopping cart, the <ProductCard /> will list items from the original data set.

So astute beginners or more experienced coders may see the problem: "customer_qty" does not exist if it hasn't been added to the cart.

So <Cart /> has access to this value, while <ProductCard /> will not because it is accessing the original object, which does not include "customer_qty:" in it, therefore it is null.

The solution


Create a variable with an anonymous function that checks first if the item has been added to the cart already. If it has, then quantity will be that item's "customer_qty", which exists in the cart items only. If it doesn't exist, then it is 0.

const quantity = (product) => {
    let quantity;
    cartItems.map((item) => {
      if (item._id === product._id) {
        quantity = item.customer_qty;
      }
    });
    return quantity;
  };

The complete Add component looks like this:

const Add = ({ product, handleRemoveProduct, handleAddProduct, cartItems }) => {
  const productExists = cartItems.find((item) => item._id === product._id);

  const quantity = (product) => {
    let quantity;
    cartItems.map((item) => {
      if (item._id === product._id) {
        quantity = item.customer_qty;
      }
    });
    return quantity;
  };

  return (
    <div className="counter">
      {productExists ? (
        <div className="show">
          <div className="minus-box">
            <i
              className="icon-minus"
              onClick={() => {
                handleRemoveProduct(product);
              }}
            ></i>
          </div>
          <div className="count">{productExists ? quantity(product) : 0}</div>
          <div className={"add-box"}>
            <i
              className="icon-pink-cross"
              onClick={() => {
                handleAddProduct(product);
              }}
            ></i>
          </div>
        </div>
      ) : (
        <div className="first-add">
          <i
            className="icon-pink-cross"
            onClick={() => {
              handleAddProduct(product);
            }}
          ></i>
        </div>
      )}
    </div>
  );
};

export default Add;


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 cordovez