Search code examples
javascriptreactjsredux

React Redux Cart Items


so my reducer looks like that. I want to add items to cart and if the item is already in the state it should increase the qty of that item. I pass object to payload but it doesnt contain the quantity field so i create it manually.

But when i add more than 2 of the same item it doesnt update further.

What is the issue here?

const init = { cartItems: [] };

export const cartReducer = (state = init, action) => {
  switch (action.type) {
    case 'ADD_TO_CART': {
      const theItem = state.cartItems.find(
        (item) => item.title === action.payload.title
      );
      if (theItem) {
        theItem.quantity++;

        return { ...state };
      } else {
        const updatedCart = [...state.cartItems, action.payload];
        return { ...state, cartItems: updatedCart };
      }
    }
    default: {
      return { ...state };
    }
  }
};


Solution

  • You cannot mutate the state, it will then not update the react component, you can try the below code for updating the quantity

    const init = { cartItems: [] };
    
    export const cartReducer = (state = init, action) => {
      switch (action.type) {
        case 'ADD_TO_CART': {
          const itemIndex = state.cartItems.findIndex(
            (item) => item.title === action.payload.title
          );
          if (itemIndex !== -1) {
            const newCartItems = [...state.cartItems];
            const newItem = {...newCartItems[itemIndex]}
            newItem.quantity += 1;
            newCartItems[itemIndex] = newItem;
    
            return { ...state, cartItems: newCartItems};
          } else {
            const updatedCart = [...state.cartItems, action.payload];
            return { ...state, cartItems: updatedCart };
          }
        }
        default: {
          return { ...state };
        }
      }
    };
    

    EDIT: The other option you can use is with Immer js it makes state management easier, though it will add in bundle size, if you have strict budget of bundle size then you would need to think of adding Immer js, Below how you can write the logic with Immer js.

    import produce from 'immer'
    
    const init = { cartItems: [] };
    
    export const cartReducer = (state = init, action) => 
    produce(state, draft => {
      switch (action.type) {
        case 'ADD_TO_CART': {
          const itemIndex = draft.cartItems.findIndex(
            (item) => item.title === action.payload.title
          );
          if (itemIndex !== -1) {
            draft.cartItems[itemIndex].quantity += 1;
          } else {
            draft.cartItems.push(action.payload)
          }
          break;
        }
        default: {
         break;
        }
      }
    })
    

    Give it a try, Immer js Documentation, Redux and Immer