Flutter中StreamBuilder加载多件购物车商品时DocumentSnapshot字段不存在怎么办?
你遇到的错误本质是前两件商品的Firestore文档中不存在你要读取的sellerName对应字段,和时序、延迟无关,核心问题和修复方案如下:
核心问题
1. 商品添加逻辑错误
你的add方法存在两处明显问题:
- 你循环所有购物车商品构建了全量数据的
cartMap变量,但最终调用set写入Firestore时完全没有用到这个变量,只写入了当前新商品的两个字段 - 你使用
SetOptions(merge: false)参数,这会直接覆盖整个文档,如果你添加不同商品时sellerName发生变化,旧商品文档中对应的旧卖家名字段会被直接删除,后续用新的卖家名读取就会找不到字段 - 额外注意:
int indexOfSeller = await getValue() ?? "";存在类型不匹配问题,int类型不能设置默认值为空字符串,要改为合法的int默认值如0。
2. 读取时未做字段存在校验
你在StreamBuilder中直接强取snapshot.data![sellerName],没有提前判断该字段是否存在于文档中,一旦字段不存在就会抛出你遇到的Bad state异常。
3. 字段设计不合理
你用动态的卖家名称作为Firestore文档的字段键属于不规范的设计,一旦卖家名称切换,所有旧文档对应的字段都会无法读取。
修复方案
第一步:优化字段设计
固定文档字段键,不要用动态的卖家名当键,比如每个商品文档固定用seller_name存卖家名称、price存对应售价、amount存商品数量。
第二步:修复商品添加逻辑
修改add方法中的写入逻辑,开启merge避免覆盖全文档:
_instance! .collection('shoppers') .doc(loginService.loggedInUserModel!.uid) .collection("cartItems") .doc(codeTest) .set({ "code": codeTest, "amount": amount, "seller_name": sellerName, "price": price }, SetOptions(merge: true)) .then((_) { notifyListeners(); });
第三步:给StreamBuilder增加异常校验
读取前先判断字段是否存在,避免抛出异常:
@override Widget build(BuildContext context) { return StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>( stream: FirebaseFirestore.instance .collection('shoppers') .doc(loginService.loggedInUserModel!.uid) .collection("cartItems") .doc(code) .snapshots(), builder: (context, snapshot) { if (snapshot.hasError) { return const Text('加载失败'); } if (!snapshot.hasData) { return const Text('No Datos'); } final docData = snapshot.data!.data() ?? {}; // 先校验字段存在且类型正确 if (docData.containsKey('price') && docData['price'] is double) { return Text( docData['price'].toStringAsFixed(2), textAlign: TextAlign.center, ); } return const Text('价格异常'); } ); }
内容的提问来源于stack exchange,提问作者SenTinel
相关产品推荐
相关产品推荐

