joshington
joshington

Reputation: 43

cant add existing product in cart in reducer in redux with react native

am working on a react native application that has a maternal shop,am using redux to work on the global state,and in my reducers i have to handle adding to cart,if product has not been existing in the cart or if product exists in the cart, my aim is just to increase its quantity without increasing the total product count here are my actions and reducers

export const ADD_TO_CART = 'ADD_TO_CART';
export const ADD_QUANTITY = 'ADD_QUANTITY';
export const SUB_QUANTITY = 'SUB_QUANTITY';

export const DELETE_ITEM = 'DELETE_ITEM';


export const addToCart = (payload) => {
    type: ADD_TO_CART,
    payload
}

export const addQuantity = (payload) => {
    type: ADD_QUANTITY,
    payload
}

export const subQuantity = (payload) => {
    type: SUB_QUANTITY,
    payload
}

export const deleteItem = (payload) => {
    type: DELETE_ITEM,
    payload
}

my reducers for the cart

import { ADD_TO_CART,DELETE_ITEM,SUB_QUANTITY,ADD_QUANTITY} from '../actions/cartItems';

const initialState = {
    itemsCount : 0,
    cartItems:[],
    cartTotalAmount:0,

}

const cartReducer = (state=initialState, action)=>{
    switch(action.type){
        case ADD_TO_CART:
            let cart = {
                id:action.payload.itemId,
                quantity:action.payload.quantity,
                name:action.payload.itemTitle,
                image:action.payload.itemImg,
                price:action.payload.itemPrice,
                cartAmount:action.payload.quantity * action.payload.itemPrice
            }
            
            if(state.itemsCount === 0){
                state.cartItems.push(cart);//just push the cart
                return {
                    ...state,
                    itemsCount:state.itemsCount+1,
                    cartTotalAmount:state.cartItems.map(item => {
                        state.cartTotalAmount+item.cartAmount
                    })
                }
            }else{
                let exists =false;
                let i =0;
                while(i<state.cartItems.length){
                    if(state.cartItems[i].id === action.payload.itemId){
                        state.cartItems[i].quantity++;
                        exists = true;
                    }
                    return{
                        ...state,
                        itemsCount:state.itemsCount
                    }
                    i++;
                }

                state.cartItems.map((key,item) => {
                    if(item.id === action.payload.itemId){
                        // {...item,quantity:item.quantity+1}
                        state.cartItems[key].quantity++;
                        exists = true
                    }
                    return {
                        ...state,
                        itemsCount:state.itemsCount,
                    }
                })
                if(!exists){
                    let _cart = {
                        id:action.payload.itemId,
                        quantity:action.payload.quantity,
                        name:action.payload.itemTitle,
                        image:action.payload.itemImg,
                        price:action.payload.itemPrice,
                        cartAmount:action.payload.quantity * action.payload.itemPrice
                    }
                    state.cartItems.push(_cart)
                    return {
                        ...state,
                        itemsCount:state.itemsCount+1,
                        cartTotalAmount:state.cartItems.map(item => {
                            state.cartTotalAmount+item.cartAmount
                        })
                    }
                }


            }
        case ADD_QUANTITY:
            return {
                ...state,
                cartItems:state.cartItems.map(
                    item => item.id === action.payload.itemId
                    ? {...item, quantity: item.quantity+1 }
                    : item 
                ),
            }
        case DELETE_ITEM:
            let newCartItems = state.cartItems.filter(
                (item) => {return item.id != action.payload.itemId}
            )
            let count = state.itemsCount-1;
            return {
                ...state,
                itemsCount:count,
                cartItems:newCartItems,
            }
        case SUB_QUANTITY:
            return {
                ...state,
                cartItems:state.cartItems.map(
                    item => item.id === action.payload.itemId 
                    ? {...item, quantity: item.quantity-1 } 
                    : item  
                ),
            }
        
        // case ADD_TO_WISH_LIST:
        //     for(let i=0; i < state.wishListItems.length; i++){
        //         if(state.wishListItems[i].id === action.item.id){
        //             return {
        //                 ...state,
        //                 wishListItems: state.wishListItems.map(item => item.id === action.item.id ?
        //                     { ...item, quantity: item.quantity+1 } :item
        //                 ) ,
        //             }
        //         }
        //         else{
        //             let updatedWishListItems = [...state.wishListItems, action.item];   
        //             let count = state.wishCount + 1;
        //         }
        //     }
        //     return{
        //         ...state,
        //         wishCount : count,
        //         wishListItems :updatedWishListItems
        //     }
        
        // case DELETE_FROM_WISH_LIST:
        //     let newWishListItems = state.wishListItems.filter(
        //         (item)=>{
        //          return item.id!=action.item.id
        //         }
        //      );
            
        //      return {
        //         ...state,
        //         wishListItems : newWishListItems , 
        //     }  
        default:
            return state
    }
        
}  

export default cartReducer;

the first case in the reducer for adding to cart when itemsCount === 0 works however when the cart has more than one item the reducer has failed to execute properly and am stuck help needed

Upvotes: 2

Views: 1434

Answers (1)

Drew Reese
Drew Reese

Reputation: 202575

Issues

  1. Don't store the itemsCount and cartTotalAmount values in state, these are easily derived from state data. Storing duplicate or derived data is anti-pattern.

    const initialState = {
      itemsCount : 0, // <-- easily computed from cart items
      cartItems:[],
      cartTotalAmount:0, // <-- easily computed from cart items
    }
    
  2. Don't mutate your state by pushing directly into your cartItems array.

    state.cartItems.push(cart); // <-- mutates state reference
    
  3. You need to search the cartItems first to see if you've already added a cart item.

Solution

case ADD_TO_CART:
  const {
    itemId,
    itemImg,
    itemPrice,
    itemTitle,
    quantity,
  } = action.payload;

  // search if item is already in cart by item id
  const inCart = state.cartItems.some(item => item.id === itemId);

  if (inCart) {
    // already in cart, shallow copy cart items
    return {
      ...state,
      cartItems: state.cartItems.map(item => item.id === itemId ? {
        // found item, shallow copy item and update quantity property
        ...item,
        quantity: item.quantity + 1,
      } : item),
    }
  } else {
    return {
      ...state,
      cartItems: [
        // shallow copy cart items
        ...state.cartItems,
        // add new cart item
        {
          id: itemId,
          quantity: quantity,
          name: itemTitle,
          image: itemImg,
          price: itemPrice,
        }
      ],
    }
  }

  ...

You can apply similar updating patterns for other action types that update the cart items.

To compute the itemsCount in your UI

const itemsCount = cartItems.reduce((count, { quantity }) => count + quantity, 0)

To compute the cartTotalAmount

const cartTotalAmount = cartItems.reduce(
  (totalAmount, { price, quantity }) => totalAmount + quantity * price,
  0,
);

These can be combined into a single calculation in a single pass

const { cartTotalAmount, itemsCount } = cartItems.reduce(
  ({ cartTotalAmount, itemsCount }, { price, quantity }) => ({
    cartTotalAmount: cartTotalAmount + quantity * price,
    itemsCount: itemsCount + quantity,
  }),
  {
    cartTotalAmount: 0,
    itemsCount: 0,
  },
);

Upvotes: 2

Related Questions