mura1
mura1

Reputation: 472

TotalPrice of the cart is displaying NaN

So I am dealing with rather a complex problem at least for me. Here I have basic cart functionality(add, remove, etc...). The problems I am facing are this. So I am able to add an item to the cart, but when I try to add the different item to the cart it is not doing it. When I try to add the same item that I added before, it is changing the number of cart items, so that is kind of working. I have a problem with a total in the Checkout Component, it is displaying NaN instead of total Price. I know it's is a quite bit of code, and I would be really grateful if someone could point me to my mistakes. Thanks

Context Api

import React from "react";

function getCartFromLocalStorage() {
  return localStorage.getItem("cart")
    ? JSON.parse(localStorage.getItem("cart"))
    : [];
}

const CartContext = React.createContext({});

function CartProvider({ children }) {
  const [cart, setCart] = React.useState(getCartFromLocalStorage());
  const [total, setTotal] = React.useState(0);
  const [cartItems, setCartItems] = React.useState(0);

  function onUpdate() {
    localStorage.setItem("cart", JSON.stringify(cart));
   
    // total
    let newTotal = cart.reduce((total, cartItem) => {
      return (total += cartItem.amount * cartItem.RegularPrice);
    }, 0);
    newTotal = parseFloat(newTotal.toFixed(3));
    setTotal(newTotal);
    
    // cartItems
    let newCartItems = cart.reduce((total, cartItem) => {
      return (total += cartItem.amount);
    }, 0);
    setCartItems(newCartItems);
  }
  React.useEffect(onUpdate, [cart]);
  
  // remove
  const removeItem = (key) => {
    setCart([...cart].filter((item) => item.key !== key));
  };
  
  // addToCart
  const addToCart = (book) => {
    const { key, image, bookName, by, RegularPrice } = book;
    let item = cart.find((item) => item.key === key);
    if (item) {
      item.amount++;
      onUpdate();
    } else {
      setCart(
        cart.concat({
          amount: 1,
          price: book.RegularPrice,
          
          ...book
        })
      );
    }
  };
  const clearCart = () => {
    setCart([]);
  };
  return (
    <CartContext.Provider
      value={{
        cart,
        cartItems,
        total,
        removeItem,
        addToCart,
        clearCart
      }}
    >
      {children}
    </CartContext.Provider>
  );
}

export { CartContext, CartProvider };

CartLink

import React from "react";
import { Link } from "react-router-dom";
import {FiShoppingCart} from 'react-icons/fi'
import { CartContext } from "../../context/cart";
export default function CartLink() {

  const { cartItems} = React.useContext(CartContext);
  return (
    <div className="cartlink__container">
      <Link to="/cart">
      <FiShoppingCart />
      </Link>
      <span className="cartlink__total">{cartItems}</span>
    </div>
  );
}

Cart Item

import React, { useContext } from "react";
import { CartContext } from "../../context/cart";
import Checkout from "./Checkout";
export default function CartItem({ key, image,bookName, RegularPrice, by, amount }) {
  const {removeItem} = useContext(CartContext)
  return (
      <div  key={key} className="cart__item">
          <img className='cart__image' src={image}  />
        <div className='cart__itemdesc'>
         <h4>{bookName}</h4>
        <h6 className='cart__by'>By: {by}</h6>
        <button
          className="cart__removebtn"
          onClick={() => {
            removeItem(key);
          }}
         >
          Remove
        </button>
        </div>  
        <span className='circle'><span className='circleone'></span></span>
        <span>{RegularPrice}</span>
        <div>
          <Checkout />
        </div>
    </div>
  );
}

Checkout

import React,{useContext} from 'react'
import { CartContext } from '../../context/cart'
import {Link, useHistory } from 'react-router-dom'
import EmptyCart from './EmptyCart';

const Checkout = () => {
  const history = useHistory()
  const {cart, total} = useContext(CartContext)
  if (cart.length === 0) {
    return <EmptyCart />;
  }

    return (
        <div>
            <Link to='/stripecontainer' className='checkout__btnOne'>Proceed to 
         Checkout</Link>    
            <h2>total : ${total}</h2>
        </div>
    )
}

export default Checkout
import React,{useState, useEffect, useContext} from 'react'
import './Home.css'
import Books from './Books'
import { BookContext } from "../../context/books";
const Home = () => {
   const {data, handleSelectCategory, currentSelectedCategory } =useContext(BookContext)
    return (
        <div className='books__container' >
          <h1 className='categories'>Categories</h1>
            {Object.keys(data).map((key, index)=>{
            let books = data[key];
            return (
              <> 
              <span key={key} onClick={() => handleSelectCategory(key)} className='books__list' >
              {books[0].category}
              </span>         
             </>
              );})}
              <Books category={currentSelectedCategory} />
        </div>
    )
}

export default Home

Upvotes: 0

Views: 1160

Answers (3)

Linda Paiste
Linda Paiste

Reputation: 42288

You have two problems in the computation of newTotal.

  1. The price for the each of the items in the cart is a string like "$17.47". Doing math operations on that string returns NaN. You should really store a number here. As a workaround you can use parseFloat, but you need to remove the $ first because parseFloat("$17.47") is NaN.

  2. You are simultaneously assigning and returning. You just want to return the new value. So don't use +=.

const newTotal = cart.reduce((total, cartItem) => {
  return total + cartItem.amount * parseFloat(cartItem.price.replace('$', ''));
}, 0);
setTotal(newTotal);

Regarding the non-unique keys: you are using a property book.key which does not seem to exist in your data set. This also makes it impossible to remove an item from the cart or to have multiple different items in the cart since you are matching based on this non-existent key. The books do have a unique property id which you should use instead, both as the key property in your JSX and for filtering the array.


The item.amount++; in addToCart is a mutation of state. You need to replace the item with a copied object.

setCart(
  cart.map((item) =>
    item.id === book.id ? { ...item, amount: item.amount + 1 } : item
  )
);

total and cartItems can be derived from the state of cart, so they don't really need to be their own state.


Thanks for including a CodeSandbox. It it so much easier to find your problem when I can run your code.

Upvotes: 3

azundo
azundo

Reputation: 6052

I think the NaN is coming because the RegularPrice property is moved to price in addToCart but then RegularPrice is used in the reducing function in onUpdate.

Upvotes: 0

WTRIX
WTRIX

Reputation: 95

I'm unfamiliar with JSon, but if you're getting NaN at the end then try a simple test of printing all the values to the screen to trace where the issue begins (where an unexpected value pops up).

As for the cart item, you say you can only add the same item to the list, then try printing the second item right before adding it to the cart. It could be a reference problem perhaps.

Upvotes: 0

Related Questions