فهرست منبع

✅ fix: 修复购物车徽章实时更新问题

- 创建购物车全局状态管理 Context (CartContext)
- 重构购物车状态同步机制,解决徽章更新不及时问题
- 移除旧的 useCart hook,统一使用 Context 管理状态
- 确保所有页面徽章实时同步购物车状态变化

现在无论用户在哪个页面操作购物车(添加/删除商品),
徽章都会立即更新,无需切换页面

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname 1 ماه پیش
والد
کامیت
74a0ff06b0

+ 4 - 1
mini/src/app.tsx

@@ -4,6 +4,7 @@ import { PropsWithChildren } from 'react'
 import { useLaunch } from '@tarojs/taro'
 import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
 import { AuthProvider } from './utils/auth'
+import { CartProvider } from './contexts/CartContext'
 
 import './app.css'
 
@@ -18,7 +19,9 @@ function App({ children }: PropsWithChildren<any>) {
   // children 是将要会渲染的页面
   return (
     <QueryClientProvider client={queryClient}>
-      <AuthProvider>{children}</AuthProvider>
+      <AuthProvider>
+        <CartProvider>{children}</CartProvider>
+      </AuthProvider>
     </QueryClientProvider>
   )
 }

+ 40 - 13
mini/src/utils/cart.ts → mini/src/contexts/CartContext.tsx

@@ -1,4 +1,4 @@
-import { useState, useEffect } from 'react'
+import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react'
 import Taro from '@tarojs/taro'
 
 export interface CartItem {
@@ -17,9 +17,22 @@ export interface CartState {
   totalCount: number
 }
 
+interface CartContextType {
+  cart: CartState
+  addToCart: (item: CartItem) => void
+  removeFromCart: (id: number) => void
+  updateQuantity: (id: number, quantity: number) => void
+  clearCart: () => void
+  isInCart: (id: number) => boolean
+  getItemQuantity: (id: number) => number
+  isLoading: boolean
+}
+
+const CartContext = createContext<CartContextType | undefined>(undefined)
+
 const CART_STORAGE_KEY = 'mini_cart'
 
-export const useCart = () => {
+export const CartProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
   const [cart, setCart] = useState<CartState>({
     items: [],
     totalAmount: 0,
@@ -37,7 +50,7 @@ export const useCart = () => {
             sum + (item.price * item.quantity), 0)
           const totalCount = savedCart.items.reduce((sum: number, item: CartItem) =>
             sum + item.quantity, 0)
-          
+
           setCart({
             items: savedCart.items,
             totalAmount,
@@ -58,15 +71,15 @@ export const useCart = () => {
   const saveCart = (items: CartItem[]) => {
     const totalAmount = items.reduce((sum, item) => sum + (item.price * item.quantity), 0)
     const totalCount = items.reduce((sum, item) => sum + item.quantity, 0)
-    
+
     const newCart = {
       items,
       totalAmount,
       totalCount
     }
-    
+
     setCart(newCart)
-    
+
     try {
       Taro.setStorageSync(CART_STORAGE_KEY, { items })
     } catch (error) {
@@ -77,7 +90,7 @@ export const useCart = () => {
   // 添加商品到购物车
   const addToCart = (item: CartItem) => {
     const existingItem = cart.items.find(cartItem => cartItem.id === item.id)
-    
+
     if (existingItem) {
       // 如果商品已存在,增加数量
       const newQuantity = Math.min(existingItem.quantity + item.quantity, item.stock)
@@ -88,7 +101,7 @@ export const useCart = () => {
         })
         return
       }
-      
+
       const newItems = cart.items.map(cartItem =>
         cartItem.id === item.id
           ? { ...cartItem, quantity: newQuantity }
@@ -108,7 +121,7 @@ export const useCart = () => {
         })
         return
       }
-      
+
       saveCart([...cart.items, item])
     }
   }
@@ -127,12 +140,12 @@ export const useCart = () => {
   const updateQuantity = (id: number, quantity: number) => {
     const item = cart.items.find(item => item.id === id)
     if (!item) return
-    
+
     if (quantity <= 0) {
       removeFromCart(id)
       return
     }
-    
+
     if (quantity > item.stock) {
       Taro.showToast({
         title: '库存不足',
@@ -140,7 +153,7 @@ export const useCart = () => {
       })
       return
     }
-    
+
     const newItems = cart.items.map(item =>
       item.id === id ? { ...item, quantity } : item
     )
@@ -167,7 +180,7 @@ export const useCart = () => {
     return item ? item.quantity : 0
   }
 
-  return {
+  const value = {
     cart,
     addToCart,
     removeFromCart,
@@ -177,4 +190,18 @@ export const useCart = () => {
     getItemQuantity,
     isLoading
   }
+
+  return (
+    <CartContext.Provider value={value}>
+      {children}
+    </CartContext.Provider>
+  )
+}
+
+export const useCart = () => {
+  const context = useContext(CartContext)
+  if (context === undefined) {
+    throw new Error('useCart must be used within a CartProvider')
+  }
+  return context
 }

+ 7 - 4
mini/src/layouts/tab-bar-layout.tsx

@@ -2,11 +2,11 @@ import React, { ReactNode } from 'react'
 import { View } from '@tarojs/components'
 import { TabBar, TabBarItem } from '@/components/ui/tab-bar'
 import Taro from '@tarojs/taro'
+import { useCart } from '@/contexts/CartContext'
 
 export interface TabBarLayoutProps {
   children: ReactNode
   activeKey: string
-  cartCount?: number
 }
 
 const tabBarItems: TabBarItem[] = [
@@ -36,7 +36,10 @@ const tabBarItems: TabBarItem[] = [
   },
 ]
 
-export const TabBarLayout: React.FC<TabBarLayoutProps> = ({ children, activeKey, cartCount }) => {
+export const TabBarLayout: React.FC<TabBarLayoutProps> = ({ children, activeKey }) => {
+  const { cart } = useCart()
+  const cartItemCount = cart.items.reduce((sum, item) => sum + item.quantity, 0)
+
   const handleTabChange = (key: string) => {
     // 使用 Taro 的导航 API 进行页面跳转
     switch (key) {
@@ -59,10 +62,10 @@ export const TabBarLayout: React.FC<TabBarLayoutProps> = ({ children, activeKey,
 
   // 动态设置购物车标签的角标
   const tabItemsWithBadge = tabBarItems.map(item => {
-    if (item.key === 'cart' && cartCount && cartCount > 0) {
+    if (item.key === 'cart' && cartItemCount > 0) {
       return {
         ...item,
-        badge: cartCount > 99 ? '99+' : cartCount
+        badge: cartItemCount > 99 ? '99+' : cartItemCount
       }
     }
     return item

+ 1 - 5
mini/src/pages/cart/index.tsx

@@ -4,7 +4,7 @@ import Taro from '@tarojs/taro'
 import { Navbar } from '@/components/ui/navbar'
 import { Button } from '@/components/ui/button'
 import { Image } from '@/components/ui/image'
-import { useCart } from '@/utils/cart'
+import { useCart } from '@/contexts/CartContext'
 import { TabBarLayout } from '@/layouts/tab-bar-layout'
 import clsx from 'clsx'
 import './index.css'
@@ -96,13 +96,9 @@ export default function CartPage() {
     </View>
   )
 
-  // 计算购物车商品总数
-  const cartItemCount = cart.items.reduce((sum, item) => sum + item.quantity, 0)
-
   return (
     <TabBarLayout
       activeKey="cart"
-      cartCount={cartItemCount}
     >
       <Navbar
         title="购物车"

+ 1 - 1
mini/src/pages/goods-detail/index.tsx

@@ -9,7 +9,7 @@ import { Button } from '@/components/ui/button'
 import { Carousel } from '@/components/ui/carousel'
 // 规格选择功能暂时移除,后端暂无规格API
 // import { GoodsSpecSelector } from '@/components/goods-spec-selector'
-import { useCart } from '@/utils/cart'
+import { useCart } from '@/contexts/CartContext'
 import './index.css'
 
 // type GoodsResponse = InferResponseType<typeof goodsClient[':id']['$get'], 200>

+ 1 - 1
mini/src/pages/goods-list/index.tsx

@@ -5,7 +5,7 @@ import Taro from '@tarojs/taro'
 import { goodsClient } from '@/api'
 import { InferResponseType } from 'hono'
 import { Navbar } from '@/components/ui/navbar'
-import { useCart } from '@/utils/cart'
+import { useCart } from '@/contexts/CartContext'
 import GoodsList from '@/components/goods-list'
 import TDesignSearch from '@/components/tdesign/search'
 

+ 1 - 1
mini/src/pages/index/index.tsx

@@ -9,7 +9,7 @@ import { goodsClient, advertisementClient } from '@/api'
 import { InferResponseType } from 'hono'
 import './index.css'
 import { useAuth } from '@/utils/auth'
-import { useCart } from '@/utils/cart'
+import { useCart } from '@/contexts/CartContext'
 import { Navbar } from '@/components/ui/navbar'
 import Taro from '@tarojs/taro'
 

+ 1 - 1
mini/src/pages/order-submit/index.tsx

@@ -8,7 +8,7 @@ import { Navbar } from '@/components/ui/navbar'
 import { Card } from '@/components/ui/card'
 import { Button } from '@/components/ui/button'
 import { useAuth } from '@/utils/auth'
-import { useCart } from '@/utils/cart'
+import { useCart } from '@/contexts/CartContext'
 import { Image } from '@/components/ui/image'
 import './index.css'
 

+ 1 - 1
mini/src/pages/search-result/index.tsx

@@ -7,7 +7,7 @@ import TDesignSearch from '@/components/tdesign/search'
 import GoodsList from '@/components/goods-list'
 import { goodsClient } from '@/api'
 import { InferResponseType } from 'hono'
-import { useCart } from '@/utils/cart'
+import { useCart } from '@/contexts/CartContext'
 import './index.css'
 
 type GoodsResponse = InferResponseType<typeof goodsClient.$get, 200>