skip to Main Content

My state is showing an empty cart . Whenever I insert a new product the state’s cartItem[] is empty (ie… not showing the previous items ) , also state.cartItems is an empty array when it is retrieved from useSelector() . Further ,Local storage not working when same item is inserted , The logic work for 2 products and then it will start incrementing the quantity of the last inserted product (not the current one).

I tried everything (from the internet), but this is now the original code . I’ve made this code for storing Items in the local storage because previously it was just replacing the previous items in the localStorage (thus storing only one)

 This is the Cart Screen 


import React,{useState} from 'react'
import MetaData from '../layout/metaData'
import CartItemCard from '../cart/CartItemCard'
import { motion } from 'framer-motion'
import Footer from '../layout/Footer'
import NoItem from '../layout/noItem.js'

import { useSelector,useDispatch } from 'react-redux'

export default function Cart() {

    const dispatch = useDispatch();


    const state = useSelector((state)=>state);

    console.log(state.cart.cartItems); // this is showing empty array




    

    const [display,setDisplay] = useState('none');

    const head = {
        product:'Product',
        price:'Price',
        name:"amarajs",
        quantity:1,
    }



  return (

    <>

    <MetaData title = "Your Cart" />
    <div className = 'container mx-auto my-[16rem] flex flex-col justify-center'>
       


       {/* {!cartItems && <NoItem/>}
       
       <div className = {`flex flex-col justify-center items-center gap-[3.2rem] blur-${display} mb-[5.4rem]`}>
            <CartItemCard heading = {head}/>
            {cartItems && cartItems.map((item)=>(
              <CartItemCard item = {item}/>
            ))}
       </div> */}
       

       <hr className = "p-4 container text-black mb-[3.2rem]"/>
       <div className = "px-[5.4rem] sub-total--section flex flex-col items-end self-end mb-[3.2rem]">
         <div className = "flex justify-center items-end gap-[1rem]">
            <p className = "text-[2.4rem]">
              SUBTOTAL
            </p>
            <p className = "total--price text-[3.2rem] font-semibold">
              ₹{'1800'}
            </p>
         </div>

         <p className = "total-subhead text-[#555] text-[1.6rem] italic">
            Shipping & taxes calculated at checkout
         </p>
       </div>


       <motion.button whileHover= {{scale:1.04}} className = " self-center text-[2.4rem] add-to-cart h-[6.4rem] w-[300px] bg-[rgb(14,14,14)] text-[#fff] rounded-[5rem] hover:bg-[#fff] hover:text-[rgb(14,14,14)]  mb-[4.4rem]" >
            checkout
        </motion.button>

    </div>
    <Footer/>

    </>
  )
}

 this is cartAction.js

import { ADD_TO_CART } from "../constants/cartConstants";
import axios from "axios";





const setLocalStorage = (...item) =>{
    
    let cartItems = [];

    const newItem = item[0][0];


    if(localStorage.getItem('cartItems')){

        cartItems = JSON.parse(localStorage.getItem('cartItems'));

        // if already present -- this is not working for more than 2 products (it will update the quantity of last inserted product instead ,not the current one)

        // const alreadyPresent = cartItems.find(i=>i.product===newItem.product);

        // if(alreadyPresent){
        //     cartItems.forEach(x =>{
        //         if(x.product===newItem.product){
        //             console.log(x.product,newItem.product)
        //             x.quantity+=1;
        //         }else{
        //             x.quantity = 1;
        //         }
        //     })
        // }
        // else{
         cartItems.push(newItem);
        // }
    }
    else{
        cartItems.push(newItem)
    }

    localStorage.setItem('cartItems',JSON.stringify(cartItems));
}




 // Add items to cart
 export const addItemsToCart = (id,quantity) => async(dispatch,getState) =>{
    

    
    const {data} = await axios.get(`http://localhost:3000/api/v1/products/${id}`);
   
    

    // const cartItems = JSON.parse(getState().cart.cartItems);
    // console.log(getState().cart)
     
    
    dispatch({
        type: ADD_TO_CART,
        payload: {
          product: data.product._id,
          name: data.product.name,
          price: data.product.price,
          image: data.product.images[0].url,
          stock: data.product.Stock,
          quantity,
        },
      });
       
     setLocalStorage(getState().cart.cartItems);

  
};

This is CartReducer.js
import { ADD_TO_CART } from "../constants/cartConstants";


export const cartReducer = (state = {cartItems:[]}, action) => {

    
    switch (action.type) {
        case ADD_TO_CART:

            const item = action.payload
            const existItem = state.cartItems.find(x => x.product === item.product)
            
            if(existItem){

                console.log("already",state.cartItems)
                return{
                    ...state,
                    cartItems: state.cartItems.map(x =>
                      x.product === existItem.product ? item : x)
                }
            }else{

                console.log(state.cartItems);
               return{
                   ...state,
                   cartItems:[...state.cartItems, item]
               }
            }


        default:
            return state

     }
   }

2

Answers


  1. It seems like there might be an issue with how you are handling the local storage and updating the Redux state in your addItemsToCart action.

    1. Local Storage Handling:
    In your setLocalStorage function, you are directly pushing the new item to cartItems. However, for the case where the item already exists, you are commenting out the code that updates the quantity.

    const setLocalStorage = (...item) => {
        let cartItems = [];
    
        const newItem = item[0][0];
    
        if (localStorage.getItem('cartItems')) {
            cartItems = JSON.parse(localStorage.getItem('cartItems'));
    
            const alreadyPresent = cartItems.find(i => i.product === newItem.product);
    
            if (alreadyPresent) {
                cartItems = cartItems.map(x =>
                    x.product === alreadyPresent.product
                        ? { ...x, quantity: x.quantity + 1 }
                        : x
                );
            } else {
                cartItems.push(newItem);
            }
        } else {
            cartItems.push(newItem);
        }
    
        localStorage.setItem('cartItems', JSON.stringify(cartItems));
    };
    

    2. Redux State Update:

    In your addItemsToCart action, it seems like you are passing the entire cartItems array to setLocalStorage, which might be causing issues.

    export const addItemsToCart = (id, quantity) => async (dispatch, getState) => {
        const { data } = await axios.get(`http://localhost:3000/api/v1/products/${id}`);
    
        dispatch({
            type: ADD_TO_CART,
            payload: {
                product: data.product._id,
                name: data.product.name,
                price: data.product.price,
                image: data.product.images[0].url,
                stock: data.product.Stock,
                quantity,
            },
        });
    
        setLocalStorage({ ...getState().cart.cartItems.slice(-1)[0] });
    };
    

    These changes should help ensure that both the local storage and the Redux state are updated correctly.

    Login or Signup to reply.
  2. From what I can see it looks like the issue is cause by const newItem = item[0][0];.

    setLocalStorage(getState().cart.cartItems);
    

    In setLocalStorage item is the array of cart items. item[0] refers to the very first cart item object. Since item[0] is not an array item[0][0] is undefined.

    const item = [{ product: 1 }];
    console.log({ "item[0]": item[0], "item[0][0]": item[0][0] });

    This causes an issue when searching the cartItems array retrieved from localStorage. The x.product === newItem.product check is never true. In fact, I believe this should be throwing an error because newItem is undefined. If it isn’t then I may just be missing something from the code.

    In either case, the "persisting the cart to localStorage" should probably be moved into the reducer so (A) you don’t write duplicate code to add an item, (B) you can persist the updated state, and (C) initialize the state from localStorage.

    const initialState = {
      // Retrieve any existing cart data, or return default empty array
      cartItems: JSON.parse(localStorage.getItem('cartItems')) ?? [];
    };
    
    export const cartReducer = (state = initialState, action) => {
      switch (action.type) {
        case ADD_TO_CART:
          const newItem = action.payload;
    
          const existItem = state.cartItems.some(
            item => item.product === newItem.product
          );
    
          let cartItems;
                
          if (existItem) {
            // Replace existing item with new quantity value
            cartItems = state.cartItems.map(
              item => item.product === newItem.product ? newItem : item
            )
          } else {
            // Add new item to cart
            cartItems = state.cartItems.concat(newItem);
          }
    
          // persist updated cart items array to localStorage
          localStorage.setItem('cartItems', JSON.stringify(cartItems));
    
          // Return new state
          return { ...state, cartItems };
    
        default:
          return state;
      }
    }
    
    export const addItemsToCart = (id, quantity) => async (dispatch) => {   
      const { data } = await axios.get(
        `http://localhost:3000/api/v1/products/${id}`
      );
           
      dispatch({
        type: ADD_TO_CART,
        payload: {
          product: data.product._id,
          name: data.product.name,
          price: data.product.price,
          image: data.product.images[0].url,
          stock: data.product.Stock,
          quantity, // <-- quantity included here
        },
      });
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search