Flutter中如何组合Riverpod StreamProvider实现链式Firestore查询
核心原因
你直接通过ref.watch(userProvider)拿到的是AsyncValue<UserModel>类型,并不是直接的UserModel实例,所以无法直接访问.nodes属性,需要先处理AsyncValue的加载、错误、有数据三种状态。
解决方案
方案1(推荐,自动响应数据变化)
直接用AsyncValue的when方法匹配状态,返回对应Stream即可,用户数据更新时会自动重新拉取节点数据:
final nodesProvider = StreamProvider<List<Node>>((ref) { final database = ref.watch(databaseProvider); return ref.watch(userProvider).when( // 加载状态下可以返回空Stream,也可以根据业务需求返回默认值Stream loading: () => Stream.empty(), error: (error, stackTrace) => Stream.error(error, stackTrace), data: (user) => database.getNodes(user.nodes), ); });
方案2(async*写法,逻辑更直观)
如果是Riverpod 2.0及以上版本,可以用async*配合ref.watch(userProvider.future)等待用户数据返回:
final nodesProvider = StreamProvider<List<Node>>((ref) async* { final database = ref.watch(databaseProvider); try { final user = await ref.watch(userProvider.future); yield* database.getNodes(user.nodes); } catch (err, stack) { yield* Stream.error(err, stack); } });
注意事项
- 以上两种实现都支持响应式更新:
userProvider数据变化时,nodesProvider会自动刷新拉取最新的节点数据 - 上层使用时直接和普通StreamProvider一样监听
AsyncValue状态即可,加载、错误状态可以直接在UI层做对应处理 - 建议优化
databaseProvider的未登录逻辑,避免直接抛UnimplementedError,可以根据业务需求跳转登录页或者返回空实例
内容的提问来源于stack exchange,提问作者Guido Lippi
相关产品推荐
相关产品推荐

