Flutter结合Provider与Firestore使用Document Reference的嵌套引用更新问题
解决方案
问题核心原因
你当前的实现没有将内部Stat的获取流和外层Check的流做组合,外层流发射Check数据时内部Stat的异步请求还未完成,后续Stat加载完成后也无法触发外层流重新发射数据,所以UI不会自动刷新。
具体实现方案
1. 引入RxDart依赖
在pubspec.yaml中添加RxDart用于流组合操作:
dependencies: rxdart: ^0.27.7 # 请使用当前最新稳定版本
2. 改造DataService的getChecks方法
使用流组合操作,将嵌套的Stat获取流和外层Check流绑定,只要任意数据更新都会触发整体流发射新值:
import 'package:rxdart/rxdart.dart'; class DataService { final FirebaseFirestore _db = FirebaseFirestore.instance; Stream<List<Check>> getChecks() { var ref = _db.collection("/users/.../.../checks/"); // 外层监听Check集合的实时变化 return ref.snapshots().switchMap((querySnapshot) { // 把每个Check文档转换成带Stat数据的Stream<Check> final checkStreams = querySnapshot.docs.map((doc) { Map _a = doc.data() as Map<dynamic, dynamic>; var _alternatives = _a['rollAlternatives']['default']; List<DocumentReference> statRefs = _alternatives['stats']; // 如果没有stat引用直接返回基础Check if (statRefs.isEmpty) { return Stream.value(Check.fromFirestore(doc, statList: [])); } // 把每个stat引用转成Stream<Stat> final statStreams = statRefs.map((ref) => getStat(ref.parent.path, ref.id)); // 组合所有Stat的流,只要有一个Stat更新就会发射最新的全量Stat列表 return CombineLatestStream.list<Stat>(statStreams).map((statList) { return Check.fromFirestore(doc, statList: statList); }); }).toList(); // 组合所有Check的流,输出最终的List<Check> return CombineLatestStream.list<Check>(checkStreams); }); } Stream<Stat> getStat(String parentPath, String docId) { // 如需Stat实时更新,保持snapshots()即可;如果只需要拉取一次,改成.get() return _db .collection(parentPath) .doc(docId) .snapshots() .map((doc) => Stat.fromFirestore(doc)); } }
3. 配合Provider使用
确保你在Widget树中使用StreamProvider监听这个流,即可自动响应数据变化刷新UI:
// 注入Provider StreamProvider<List<Check>>( create: (context) => DataService().getChecks(), initialData: const [], child: const YourPage(), ) // 页面中使用 Consumer<List<Check>>( builder: (context, checks, child) { if (checks.isEmpty) { return const CircularProgressIndicator(); } return ListView.builder( itemCount: checks.length, itemBuilder: (context, index) { final check = checks[index]; return CheckItem(check: check); }, ); } )
可选优化
可以给Check类增加一个isStatsLoading字段,在Stat加载过程中展示占位符,避免首次渲染出现空白。
内容的提问来源于stack exchange,提问作者Darkade
相关产品推荐
相关产品推荐

