0

Hi i am pretty new to React.

Here is my code:

const cartCtx=useContext(CartContext);

const cartItems = (
    <ul className={classes['cart-items']}>
      {cartCtx.items.map((item) => (
        <CartItem 
        key={item.id}
        name={item.name}
        amount={item.amount}
        price={item.price}
        onAdd={cartCtx.addItem(item)}
....

I am trying to add item by calling onAdd function which existed in my ReactContext.

However, I get this error when running:

Warning: Cannot update a component (CartProvider) while rendering a different component (Cart). To locate the bad setState() call inside Cart.

After I change onAdd function call to an arrow function:

const cartItems = (
    <ul className={classes['cart-items']}>
      {cartCtx.items.map((item) => (
        <CartItem 
        key={item.id}
        name={item.name}
        amount={item.amount}
        price={item.price}
        onAdd={()=>cartCtx.addItem(item)}
....

The problem gets resolved.

Here is my onAdd function inside ReactContext:

const defaultCartState = {
  items: [],
  totalAmount: 0
};

const cartReducer = (state, action) => {

  if (action.type === 'ADD') {
    
    const updatedTotalAmount = state.totalAmount + action.item.price * action.item.amount;

    const existingCartItemIndex=state.items.findIndex((item)=>item.id===action.item.id);

    const existingCartItem=state.items[existingCartItemIndex]

   
    let updatedItems;
    let updateItem;
    if (existingCartItem){
       
       updateItem={...existingCartItem,
       amount:action.item.amount+existingCartItem.amount
      }
       updatedItems=[...state.items]
       updatedItems[existingCartItemIndex]=updateItem;
    }
    else{
     updatedItems = state.items.concat(action.item);}

    return {
      items: updatedItems,
      totalAmount: updatedTotalAmount
    };
    
  }
  return defaultCartState;
};

const CartProvider = (props) => {
  const [cartState, dispatchCartAction] = useReducer(cartReducer, defaultCartState);

  const addItemToCartHandler = (item) => {
    dispatchCartAction({type: 'ADD', item: item});
  };


  const cartContext = {
    items: cartState.items,
    totalAmount: cartState.totalAmount,
    addItem: addItemToCartHandler
  };

  return (
    <CartContext.Provider value={cartContext}>
      {props.children}
    </CartContext.Provider>
  );
};

export default CartProvider;

Does anyone know why this happens and what is the logic behind the scene?

  • 1
    This: `cartCtx.addItem(item)` is not a function but a function *call*. It calls the function right away, and uses the return value as `onAdd` value. Using a regular function would look like this: `onAdd={function() { cartCtx.addItem(item); }}` (this is the non-arrow version of your arrow version) see here for the generic answer: https://stackoverflow.com/questions/16310423/addeventlistener-calls-the-function-without-me-even-asking-it-to –  Jan 20 '22 at 15:21
  • Thanks so much @ChrisG – Misaka911 Jan 20 '22 at 15:33

0 Answers0