Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Function only works on every second click

Beginner to React here, currently learning how to build a shopping cart.

My addToCart() function has been passed as a function to an add-to-cart button onClick event handler, which is then supposed to update the cart array state via setCart.

The problem is, whenever I click the button (which is supposed to increment quantity), the cart array only updates on every second click (e.g. i click on Apple’s add to cart, and cart remains at {id: 1, quantity:2} , and on the second click, it updates to {id:1, quantity:3}.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Also, when I click on add to cart for Orange (which has an id of 3), the first click will increment cart id 1 (e.g. i end up with [{id: 1, quantity: 3}], while the second click gives [{id: 1, quantity: 3}, {id: 3, quantity: 1}].

Would appreciate any help. Thank you.

const shoppingList = [
  { id: 1, name: "Apple", image: apple, price: 1.5 },
  { id: 2, name: "Pear", image: pear, price: 2.5 },
  { id: 3, name: "Orange", image: orange, price: 3.5 },
  { id: 4, name: "Banana", image: banana, price: 4.5 },
  { id: 5, name: "Watermelon", image: watermelon, price: 5.5 },
];

export default shoppingList;

import shoppingList from "../Data/ShoppingList";
import { useState, useRef } from "react";
import AddToCart from "./AddToCart";

const ShoppingMenu = () => {
  const [cart, setCart] = useState([{ id: 1, quantity: 2 }]);

  function getItemID(id) {
    const itemID = shoppingList.find((shoppingItem) => id == shoppingItem.id);

    return itemID.id;
  }

  function addToCart(itemID) {
    const newCartItem = cart.find((cartItem) => cartItem.id == itemID);

    console.log({ newCartItem, cart });

    if (newCartItem === undefined) {
      const cartReplica = cart;
      setCart([...cartReplica, { id: itemID, quantity: 1 }]);
      console.log(cart);
    } else {
      console.log("exists");
      const cartReplica = cart;
      cartReplica.map((cartProduct) =>
        cartProduct.id == itemID
          ? setCart([{ ...cartProduct, quantity: cartProduct.quantity + 1 }])
          : cartProduct
      );
      console.log(cart);
    }
  }

  const mapShoppingMenu = shoppingList.map((shoppingItem) => {
    return (
      <div id={shoppingItem.id} className="item-card">
        <img src={shoppingItem.image} alt="" className="item-image" />
        <h2>{shoppingItem.name}</h2>
        <h3>${shoppingItem.price}</h3>
        <AddToCart />
        <button
          id={shoppingItem.id}
          onClick={(e) => {
            let itemID = getItemID(e.target.id);
            console.log(itemID);
            addToCart(itemID);
          }}
        >
          Add To Cart
        </button>
        {/* {console.log(cart)} */}
      </div>
    );
  });

  return <div className="shopping-list">{mapShoppingMenu}</div>;
};

export default ShoppingMenu;

Tried modifying addToCart, tried modifying the event handler for button..

>Solution :

Actually, your code works fine. The problem is that you don’t understand how the state is updated in a functional component.

setCart is asynchronous, meaning that the rest of your function will be executed before the value of cart changes. Why ? Because React doesn’t immediately update the state. Instead, it schedules the update to be processed later.

So when you are calling console.log(cart) after setCart, the value logged into the console will be the previous value, not the new one. But if you render the value of cart you will see that it has been updated.

Here is a quick example to illustrate : Let’s say that i have a counter component :

function Counter() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1); // State update is scheduled asynchronously
    console.log(count); // This may not show the updated count immediately
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
}

If i click on "Increment", the logged value will be 0, but the value rendered will be 1, because when console.log is called, count hasn’t been updated yet, but a few ms laters the component will be rerendered with the new value.

I know that this can be a challenging topic for beginners in React, so if you have any questions, don’t hesitate to ask !

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading