如何在Flutter中结合Riverpod StreamProvider?
How to combine Riverpod StreamProvider in Flutter?
我一直在尝试合并两个 Riverpod StreamProvider。
目标是根据来自 Firestore 的其他数据对 Firestore 执行查询以获取数据,如下所示:
- 从 firestore 文档中获取用户数据
- 使用该数据执行另一个查询
这是我共享 FirestoreDatabase class 实例的数据库提供商:
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);
}
}
}
});
我一直在尝试合并两个 Riverpod StreamProvider。 目标是根据来自 Firestore 的其他数据对 Firestore 执行查询以获取数据,如下所示:
- 从 firestore 文档中获取用户数据
- 使用该数据执行另一个查询
这是我共享 FirestoreDatabase class 实例的数据库提供商:
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);
}
}
}
});