购物车的总价格显示 NaN

时间:2021-03-29 20:47:15

标签: javascript node.js reactjs redux context-api

所以至少对我来说,我正在处理一个相当复杂的问题。在这里,我有基本的购物车功能(添加、删除等...)。我面临的问题是这样的。所以我可以将一个项目添加到购物车,但是当我尝试将不同的项目添加到购物车时,它并没有这样做。当我尝试添加我之前添加的相同项目时,它正在改变购物车项目的数量,所以这是一种工作。我在结帐组件中遇到总计问题,它显示 NaN 而不是总价格。我知道这是一段相当长的代码,如果有人能指出我的错误,我将不胜感激。谢谢

上下文 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 };

购物车链接

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>
  );
}

购物车项目

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>
  );
}

结帐

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

3 个答案:

答案 0 :(得分:2)

您在计算 newTotal 时有两个问题。

  1. price 中每一项的 cart 是一个 string,如 "$17.47"。对该 string 进行数学运算返回 NaN。你真的应该在这里存储一个 number。作为解决方法,您可以使用 parseFloat,但您需要先删除 $,因为 parseFloat("$17.47")NaN

  2. 你同时分配和返回。您只想return 新值。所以不要使用 +=

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

关于非唯一键:您使用的属性 book.key 似乎不存在 in your data set。这也使您无法从购物车中删除商品或购物车中有多个不同的商品,因为您是根据此不存在的 key 进行匹配的。这些书籍确实有一个独特的属性 id,您应该将其用作 JSX 中的 key 属性和过滤数组。


item.amount++; 中的 addToCart 是状态的突变。您需要用复制的对象替换 item

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

totalcartItems 可以从 cart 的状态派生,所以它们并不需要是它们自己的状态。


感谢您提供 CodeSandbox。当我可以运行您的代码时,更容易找到您的问题。

答案 1 :(得分:0)

我不熟悉 JSon,但如果您在最后得到 NaN,那么尝试一个简单的测试,将所有值打印到屏幕上以跟踪问题开始的位置(弹出意外值的位置)。

至于购物车项目,您说您只能将同一项目添加到列表中,然后在将其添加到购物车之前尝试打印第二个项目。这可能是一个参考问题。

答案 2 :(得分:0)

我认为 NaN 即将到来是因为 RegularPrice 属性被移动到 price 中的 addToCart 但随后 RegularPrice 用于 {{} {1}}。