如何用Riverpod Stream Provider获取Firebase的<List<Model>>流?
Riverpod结合Firebase实现StreamProvider时的类型错误问题
我正尝试参考Riverpod官方文档实现Stream Provider,但结合Firebase使用时遇到问题。
我先创建了如下Stream Provider:
final streamProvider = StreamProvider<List<Model>>((ref) async* { var modelList = <Model>[]; yield modelList; });
接着接入Firebase的流:
final streamProvider = StreamProvider<List<Model>>((ref) async* { final snapshots = FirebaseFirestore.instance.collection('collection'); var modelList = <Model>[]; yield modelList; });
snapshots返回类型为Stream<QuerySnapshot<Map<String, dynamic>>>,我需从中获取文档列表,但无法使用snapshots.docs等方法(可能已弃用)。
尝试用以下代码转换:
var list = snapshots.map( (snapshot) => snapshot.docs.map( (doc) => Model.fromSnapshot(doc), ), );
这返回Stream<Iterable<Model>>,添加.toList()则返回Stream<List<Model>>。
编写完整代码时:
final streamProvider = StreamProvider<List<Model>>((ref) async* { final snapshots = FirebaseFirestore.instance.collection('collection'); var list = snapshots.map( (snapshot) => snapshot.docs.map( (doc) => Model.fromSnapshot(doc), ), ); var modelList = <Model>[]; await for (final item in list) { modelList = [...modelList, item]; } yield modelList; });
出现错误:
The element type Iterable<Exercise>' can't be assigned to the list type 'Exercise'
请问我哪里出错了?
问题原因与修复方案
核心错误点
你在await for循环里,把item(类型是Iterable<Model>)直接放进了List<Model>里,这就导致了类型不匹配——列表需要单个Model对象,你却塞了一个可迭代集合进去。
另外,你的代码逻辑绕了弯路:Firestore的collection.snapshots()本身就是一个流,不需要手动用await for去拼接列表,直接转换流的输出即可。
正确实现方式
直接在map转换时把Iterable<Model>转成List<Model>,然后把这个处理好的流返回给StreamProvider就行:
final streamProvider = StreamProvider<List<Model>>((ref) { // 注意:这里不需要async*,直接返回处理后的流 return FirebaseFirestore.instance.collection('collection').snapshots().map( (snapshot) => snapshot.docs .map((doc) => Model.fromSnapshot(doc)) .toList(), // 这里直接转成List<Model> ); });
补充说明
- 原代码里的
final snapshots = FirebaseFirestore.instance.collection('collection');少了.snapshots(),这才是获取Firestore数据变更流的正确方法,之前的snapshots其实是CollectionReference类型,不是流,这也是你一开始没法用.docs的原因。 - StreamProvider可以直接接收一个
Stream<T>类型的返回值,不需要用async*生成器,除非你需要额外的异步逻辑处理。 - 如果需要初始空列表,可以在转换时处理,或者在UI层监听流的时候处理空状态。
内容的提问来源于stack exchange,提问作者Jason Dupree
相关产品推荐
相关产品推荐

