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
相关产品推荐
相关产品推荐

