Flutter Riverpod购物车异常:数量不实时更新、商品无法添加
问题排查与修复方案
核心问题分析
你的购物车功能出现两个问题的根本原因在于StateNotifier状态更新机制错误和商品对象判断逻辑失效:
- 自定义的
_carts列表未与StateNotifier的state绑定,修改后未触发UI刷新 - 直接修改
product.qty但未通知StateNotifier更新状态,导致UI无法实时感知变化 contains(product)默认判断对象引用而非商品ID,导致重复添加或数量更新失效ProductModel.fromJson中qty的赋值错误(json[1]应为json['qty'])
逐步修复代码
1. 修复ProductModel类
重写==和hashCode,基于商品ID判断是否为同一商品;修正fromJson的qty赋值:
class ProductModel { int? id; int qty = 1; String? product_name; String? product_description; int? product_price; String? images; ProductModel({this.id, required this.qty, this.product_name, this.product_description, this.product_price, this.images}); ProductModel.fromJson(Map<String, dynamic> json) { id = int.tryParse(json['id']); product_name = json['product_name']; product_description = json['product_description']; product_price = int.tryParse(json['product_price']); images = json['images']; qty = json['qty'] ?? 1; // 修正为json['qty']而非json[1] } // 重写==和hashCode,基于id判断是否为同一商品 @override bool operator ==(Object other) => identical(this, other) || other is ProductModel && runtimeType == other.runtimeType && id == other.id; @override int get hashCode => id.hashCode; }
2. 修复Productstore类
移除自定义_carts列表,直接使用StateNotifier的state;所有修改操作后必须更新state以触发UI刷新:
import 'package:five_star/ProductModel.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; class Productstore extends StateNotifier<List<ProductModel>>{ Productstore(): super([]); void addToCart(ProductModel product) { // 查找是否已存在同ID商品 final existingProduct = state.firstWhere( (p) => p.id == product.id, orElse: () => ProductModel(id: -1, qty: 0), // 占位无效商品 ); if (existingProduct.id != -1) { // 已存在则更新数量 final updatedList = state.map((p) { if (p.id == product.id) { return ProductModel( id: p.id, qty: p.qty + 1, product_name: p.product_name, product_description: p.product_description, product_price: p.product_price, images: p.images, ); } return p; }).toList(); state = updatedList; } else { // 不存在则添加新商品 state = [...state, product]; } } void removeFromCart(ProductModel product) { state = state.where((p) => p.id != product.id).toList(); } void removeCartqty(ProductModel product) { final updatedList = state.map((p) { if (p.id == product.id) { if (p.qty == 1) { // 数量为1时移除商品 return null; } else { // 数量减1 return ProductModel( id: p.id, qty: p.qty - 1, product_name: p.product_name, product_description: p.product_description, product_price: p.product_price, images: p.images, ); } } return p; }).whereType<ProductModel>().toList(); state = updatedList; } void addCartqty(ProductModel product) { final updatedList = state.map((p) { if (p.id == product.id) { return ProductModel( id: p.id, qty: p.qty + 1, product_name: p.product_name, product_description: p.product_description, product_price: p.product_price, images: p.images, ); } return p; }).toList(); state = updatedList; } }
3. 修复product_detail页面
移除重复的ref.read,确保UI能监听state变化;从state中获取当前商品的最新数量:
import 'package:five_star/Cart.dart'; import 'package:five_star/ProductModel.dart'; import 'package:five_star/ProductStore.dart'; import 'package:five_star/all_products.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:five_star/home.dart'; final cartprovider = StateNotifierProvider<Productstore, List<ProductModel>>((ref) => Productstore()); class product_detail extends ConsumerStatefulWidget { const product_detail({super.key}); @override product_detailState createState() => product_detailState(); } class product_detailState extends ConsumerState<product_detail> { @override Widget build(BuildContext context) { final productArg = ModalRoute.of(context)!.settings.arguments as ProductModel; // 监听购物车状态,获取当前商品的最新信息 final cartItems = ref.watch(cartprovider); final currentProduct = cartItems.firstWhere( (p) => p.id == productArg.id, orElse: () => productArg, // 如果未加入购物车,使用原始商品 ); final cartNotifier = ref.read(cartprovider.notifier); return Scaffold( appBar: AppBar( title: const Text('PRODUCT DETAIL'), backgroundColor: Colors.orange, ), body: ListView( children: [ Container( height: MediaQuery.of(context).size.height, color: Colors.white, child: Column( children: [ Padding( padding: const EdgeInsets.all(10.0), child: Container( height: 160, width: double.infinity, child: Card( color: Colors.white, child: Image.network("https://hometronix.co.tz/admin/images/products/${productArg.images}"), ), ), ), Center( child: Padding( padding: const EdgeInsets.all(8.0), child: Text( productArg.product_name ?? '', style: const TextStyle( color: Colors.black, fontSize: 20, fontWeight: FontWeight.bold), ), ), ), Center( child: Padding( padding: const EdgeInsets.all(4.0), child: Text( "${productArg.product_price ?? 0}", style: const TextStyle(color: Colors.black, fontSize: 20), ), ), ), Padding( padding: const EdgeInsets.all(10.0), child: Container( height: 200, width: MediaQuery.of(context).size.width, child: Center( child: Text(productArg.product_description ?? '')), ), ), Padding( padding: const EdgeInsets.all(8.0), child: SizedBox( height: 50, width: MediaQuery.of(context).size.width / 2, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( onPressed: () { cartNotifier.removeCartqty(productArg); }, icon: const Icon( Icons.remove, color: Colors.red, )), Text( "${currentProduct.qty}", style: const TextStyle(color: Colors.black), ), IconButton( onPressed: () { cartNotifier.addCartqty(productArg); }, icon: const Icon( Icons.add, color: Colors.green, )), ], ), ), ), Padding( padding: const EdgeInsets.all(8.0), child: SizedBox( height: 50, width: MediaQuery.of(context).size.width / 2, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.orange, foregroundColor: Colors.black, ), onPressed: () { cartNotifier.addToCart(productArg); }, child: const Text( 'add to cart', style: TextStyle(color: Colors.white), ), ), ), ), ], ), ) ], ), ); } }
修复说明
- StateNotifier状态更新:所有购物车操作后都通过生成新列表的方式更新
state,确保Riverpod能通知UI刷新 - 商品唯一性判断:通过重写
==和hashCode,基于商品ID判断是否为同一商品,解决contains判断失效问题 - 不可变对象更新:修改商品数量时生成新的
ProductModel对象,符合Riverpod的不可变状态管理原则 - UI数据同步:从
ref.watch(cartprovider)中获取最新的商品数量,确保UI展示的是购物车中的实时数据
内容的提问来源于stack exchange,提问作者salmoa
相关产品推荐
相关产品推荐

