You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React项目中点击加入购物车后购物车计数不增加的问题求助

React项目中点击加入购物车后购物车计数不增加的问题求助

我正在自己的项目里实现加入购物车功能,但是点击加入购物车按钮后,App.tsx里购物车部分的状态没有变化,导航栏里的购物车商品数量也没法更新。所有需要的库都已经安装完成,网站也能正常运行,就是购物车的计数一直不涨,有没有大佬帮忙看看哪里出问题了?

App.tsx

import { Button,Badge, Container, Form, Nav, Navbar } from 'react-bootstrap'

import { Link, Outlet } from 'react-router-dom'

import Footer from './components/footer/Footer.js'

import { useContext, useEffect } from 'react'

import { Store } from './Store.js'

function App() {

const {

state: { mode, cart },

dispatch,

} = useContext(Store)

useEffect(() => {

document.body.setAttribute('data-bs-theme', mode)

}, [mode])

const switchModeHandler = () => {

dispatch({ type: 'SWITCH_MODE' })

}

return (

<div className="d-flex flex-column vh-100">

<header>

<Navbar bg="dark" variant="dark" expand="lg">

<Container>

<Navbar.Brand >

<Link to={`/`} className="no-underline">

ThriftTrade

</Link>

</Navbar.Brand>

<Nav className="me-auto">

<Nav.Link href="/buy">Buy</Nav.Link>

<Nav.Link href="/sell">Sell</Nav.Link>

<Nav.Link href="/offers">Offers</Nav.Link>

<Nav.Link href="/auction">Auction</Nav.Link>

<Nav.Link href="/categories">Categories</Nav.Link>

<Nav.Link href="/about_us">About Us</Nav.Link>

</Nav>

<Form className="d-flex">

<Form.Control

type="search"

placeholder="Search"

className="me-2"

aria-label="Search"

/>

<Button variant="dark">Search</Button>

</Form>

</Container>

<Nav>

<Link to="/cart" className="nav-link">

Cart

{cart.cartItems.length > 0 && (

<Badge pill bg="danger">

{cart.cartItems.reduce((a, c) => a + c.quantity, 0)

}

</Badge>

)}

</Link>

<a href="/login" className="nav-link">

Sign In

</a>

</Nav>

</Navbar>

</header>

<main>

{/* <Container> */}

<Outlet />

{/* </Container> */}

</main>

<Footer />

</div>

)

}

export default App

utils.ts

import { ApiError } from './types/Apierror.js'

import { CartItem } from './types/Cart.js'

import { Product } from './types/Product.js'

export const getError = (error: ApiError) => {

return error.response && error.response.data.message

? error.response.data.message

: error.message

}

export const convertProductToCartItem = (product: Product): CartItem => {

const cartItem: CartItem = {

_id: product._id,

name: product.name,

slug: product.slug,

image: product.image,

price: product.price,

countInStock: product.countInStock,

quantity: 1,

}

return cartItem

}

ProductItem.tsx

import { Button, Card } from 'react-bootstrap'

import { Link } from 'react-router-dom'

import { Product } from '../types/Product.js'

import Rating from './Rating.js'

import { convertProductToCartItem } from '../utils.js'

import { Store } from '../Store.js'

import { useContext } from 'react'

import { CartItem } from '../types/Cart.js'

import { toast } from 'react-toastify'

function ProductItem({ product }: { product: Product }) {

const { state, dispatch } = useContext(Store)

const {

cart: { cartItems },

} = state

const addToCartHandler = (item: CartItem) => {

const existItem = cartItems.find((x) => x._id === product._id)

const quantity = existItem ? existItem.quantity + 1 : 1

if (product.countInStock < quantity) {

alert('Sorry. Product is out of stock')

return

}

dispatch({

type: 'CART_ADD_ITEM',

payload: { ...item, quantity },

})

toast.success('Product added to the cart')

}

return (

<Card>

<Link to={`/product/${product.slug}`}>

<img src={product.image} className="card-img-top" alt={product.name} />

</Link>

<Card.Body>

<Link className="product_name_class" to={`/product/${product.slug}`}>

<Card.Title className="product-name">{product.name}</Card.Title>

</Link>

<Rating rating={product.rating} numReviews={product.numReviews} />

<Card.Text>${product.price}</Card.Text>

{product.countInStock === 0 ? (

<Button variant="light" disabled>

Out of stock

</Button>

) : (

<Button

onClick={() => addToCartHandler(convertProductToCartItem(product))}

>

Add to cart

</Button>

)}

</Card.Body>

</Card>

)

}

export default ProductItem

Store.tsx

import React from "react";

import { Cart, CartItem } from "./types/Cart.js";

// Define the AppState type

type AppState = {

mode: string;

cart: Cart;

};

// Define the initial state

const initialState: AppState = {

mode: localStorage.getItem("mode") ?? (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"),

cart: {

cartItems: localStorage.getItem("cartItems")

? JSON.parse(localStorage.getItem("cartItems")!)

: [],

shippingAddress: localStorage.getItem("shippingAddress")

? JSON.parse(localStorage.getItem("shippingAddress")!)

: {},

paymentMethod: localStorage.getItem("paymentMethod") ?? "PayPal",

itemsPrice: 0,

shippingPrice: 0,

taxPrice: 0,

totalPrice: 0,

},

};

// Define the supported actions

type Action =

| { type: "SWITCH_MODE" }

| { type: "CART_ADD_ITEM"; payload: CartItem }

| { type: "UPDATE_SHIPPING_ADDRESS"; payload: Cart["shippingAddress"] };

// Define the reducer function

function reducer(state: AppState, action: Action): AppState {

switch (action.type) {

case "SWITCH_MODE": {

const mode = state.mode === "dark" ? "light" : "dark";

localStorage.setItem("mode", mode);

return { ...state, mode };

}

case "CART_ADD_ITEM": {

const newItem = action.payload;

const existItem = state.cart.cartItems.find((item: CartItem) => item._id === newItem._id);

const cartItems = existItem

? state.cart.cartItems.map((item: CartItem) => (item._id === existItem._id ? newItem : item))

: [...state.cart.cartItems, newItem];

localStorage.setItem("cartItems", JSON.stringify(cartItems));

return { ...state, cart: { ...state.cart, cartItems } };

}

case "UPDATE_SHIPPING_ADDRESS": {

const shippingAddress = action.payload;

localStorage.setItem("shippingAddress", JSON.stringify(shippingAddress));

return {

...state,

cart: { ...state.cart, shippingAddress },

};

}

default:

return state;

}

}

// Create the default dispatch function

const defaultDispatch: React.Dispatch<Action> = () => initialState;

// Create the Store context

const Store = React.createContext({

state: initialState,

dispatch: defaultDispatch,

});

// Create the StoreProvider component

function StoreProvider(props: React.PropsWithChildren<{}>) {

const [state, dispatch] = React.useReducer<React.Reducer<AppState, Action>>(

reducer,

initialState

);

return <Store.Provider value={{ state, dispatch }} {...props} />;

}

// Export the Store and StoreProvider

export { Store, StoreProvider };

Product.ts

export type Product = {

_id: string

name: string

slug: string

image: string

category: string

brand: string

price: number

countInStock: number

description: string

rating: number

numReviews: number

}

备注:内容来源于stack exchange,提问作者Sajjad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 09:20:30