使用Riverpod实现购物车时遇空值检查错误求助
购物车页面Null Check错误排查与修复
错误信息
════════ Exception caught by widgets library ═══════════════════════════════════
The following _CastError was thrown building:
Null check operator used on a null value
核心问题分析
- CartItem模型设计矛盾:构造函数用
required修饰参数,但成员变量却定义为可空类型(String?、int?),导致实例化后仍可能出现null值,后续强制解包(!)时触发错误。 - CartRepository逻辑缺陷:
addItem参数未指定类型,存在传入null的风险;- 用两个独立
if判断商品是否存在,逻辑冗余且可能导致重复执行; - 初始添加商品时
qty设为0,后续更新时直接用value.qty!强制解包,若qty为null会触发错误;
- UI层未处理null情况:购物车页面直接用
itemsName!强制解包,未考虑字段为null的场景。
修复后的代码
1. CartItem模型(修正可空性)
import 'package:ecommerceriverpod/src/features/cart/domain/item.dart'; import 'package:ecommerceriverpod/src/features/products/domain/product.dart'; class CartItem { final String productId; final String itemsName; final String price; final String image; int qty; // 数量可修改,不设final CartItem({ required this.productId, required this.itemsName, required this.price, required this.image, required this.qty, }); }
2. CartRepository控制器(优化逻辑与类型)
class CartRepository extends Notifier<Map<String, CartItem>> { @override Map<String, CartItem> build() { return {}; } void addItem({ required String productId, required String price, required String title, required String name, required String image, }) { if (state.containsKey(productId)) { state.update( productId, (value) => CartItem( productId: value.productId, itemsName: value.itemsName, price: value.price, image: value.image, qty: value.qty + 1, // qty已不可空,无需强制解包 ), ); } else { state.putIfAbsent( productId, () => CartItem( productId: productId, itemsName: title, price: price, image: image, qty: 1, // 初始数量设为1,符合购物逻辑 ), ); } } void removeItem(String id) { if (state.containsKey(id)) { final currentItem = state[id]!; if (currentItem.qty > 1) { state.update( id, (value) => CartItem( itemsName: value.itemsName, price: value.price, image: value.image, productId: value.productId, qty: value.qty - 1, ), ); } else { // 数量为1时移除商品,避免空条目 state.remove(id); } } } void clearCart() { state.clear(); } int? getCartItem(String id) { return state[id]?.qty; } } final cartRepositoryProvider = NotifierProvider<CartRepository, Map<String, CartItem>>(CartRepository.new);
3. 购物车页面(简化逻辑,避免null解包)
class CartPage extends ConsumerWidget { const CartPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { // 提前转换为列表,避免重复计算 final cartItems = ref.watch(cartRepositoryProvider).values.toList(); return Scaffold( appBar: AppBar( title: const Text("Cart"), ), body: SafeArea( child: Column( children: [ Expanded( child: ListView.builder( itemCount: cartItems.length, itemBuilder: (context, index) { final item = cartItems[index]; return ListTile( title: Text(item.itemsName), subtitle: Text("\$${item.price} x ${item.qty}"), leading: Image.network(item.image), ); }, ), ) ], ), ), ); } }
修复说明
- 模型层:将CartItem的核心字段改为不可空类型,从根源杜绝null值出现;
- 逻辑层:明确参数类型、优化判断逻辑,初始数量设为1符合用户购物习惯,移除商品时处理数量为0的场景;
- UI层:提前转换购物车条目为列表,直接访问不可空字段,无需强制解包,同时优化展示内容。
内容的提问来源于stack exchange,提问作者Mohammed M
相关产品推荐
相关产品推荐

