flutter - 如何在 Flutter 中结合 Riverpod StreamProvider?
问题描述
我一直在尝试结合两个 Riverpod StreamProvider。目标是根据来自 Firestore 的其他数据对 Firestore 执行查询以获取数据,如下所示:
- 从 Firestore 文档中获取用户数据
- 使用该数据执行另一个查询
这是我共享 FirestoreDatabase 类实例的数据库提供程序:
final databaseProvider = Provider<FirestoreDatabase>((ref) {
final auth = ref.watch(authStateChangesProvider);
if (auth.data?.value?.uid != null) {
return FirestoreDatabase(uid: auth.data!.value!.uid);
}
throw UnimplementedError();
});
然后我创建了一个 StreamProvider 来获取用户的数据
final userProvider = StreamProvider<UserModel>((ref) {
final database = ref.watch(databaseProvider);
return database.getUser();
});
现在我需要创建最后一个提供者,但我无法让它工作。这是我从现在开始写的:
final nodesProvider = StreamProvider<List<Node>>((ref) {
final database = ref.watch(databaseProvider);
final user = ref.watch(userProvider);
//... some code to await user data fetching
// user.nodes contains the list I need to pass in order to perform the query
return database.getNodes(user.nodes);
});
有人可以帮助我或给我提示吗?提前致谢
解决方案
根据个人经验,我建议远离 StreamProviders,除非它只有一层深(没有依赖于其他流的流)。
相反,Riverpod 有一个.last
提供程序,它公开流中的最后一个值。通话ref.watch
将让您收听它和任何更新。
final databaseProvider = FutureProvider<FirestoreDatabase>((ref) async {
final auth = await ref.watch(authStateChangesProvider.last);
if (auth.data?.value?.uid != null) {
return FirestoreDatabase(uid: auth.data!.value!.uid);
}
throw StateError('auth uid is null so no database could be created');
});
final nodesProvider = FutureProvider<List<Node>>((ref) async {
// you can Future.wait these if you want
final database = await ref.watch(databaseProvider);
final user = await ref.watch(userProvider.last);
return database.getNodes(user.nodes);
});
我认为这会起作用,尽管我的语法可能有点错误(在 SO 文本区域中写这个)。另一方面,有一些方法可以在流中收听流,但我从来没有运气。这就是我认为的样子。
final databaseProvider = StreamProvider<FirestoreDatabase?>((ref) async* {
// Or any loading value really... Idk if I'd actually do this
yield null;
for await (final authState in ref.watch(authStateChangesProvider.stream)) {
if (auth.data?.value?.uid != null) {
yield FirestoreDatabase(uid: auth.data!.value!.uid);
}
}
});
final nodesProvider = StreamProvider<List<Node>?>((ref) async* {
// [Edit] You could probably use combineStream from rxDart here
for await (final database in await ref.watch(databaseProvider.stream)) {
if (database != null) {
for await (final user in ref.watch(userProvider.stream)) {
yield database.getNodes(user.nodes);
}
}
}
});
推荐阅读
- node.js - 如何从启用身份验证的 NodeJS 应用程序创建 MongoDB 用户?
- java - Jacoco 支持 apache wicket?
- cryptography - HD钱包的公钥子密钥对应的私钥是什么?
- coldfusion - 如何检查 cfcatch 块中的本机代码错误?
- android - 谷歌地图未在真实设备中显示
- oracle - 如何提高 FORALL 插入例程的性能?
- node.js - 如何在单个请求中读取 Firestore 中的多个文档?
- java - SpringBoot MongoDB CrudRepositoryCustom Implementation 的目录结构应该如何组织?
- neo4j - Neo4j Cypher:匹配数组中的多个属性值
- android - 告诉我如何将 GridView 放在 ListView 中(我在创建适配器时遇到了很多麻烦)