将 FutureProvider 变成提供者
Turning a FutureProvider into a Provider
我使用 FirebaseAuth
进行身份验证,并且定义了以下提供程序:
final _authStateChangesProvider = StreamProvider<User>(
(ref) => ref.watch(authServiceProvider).authStateChanges);
数据库依赖于用户,所以我只能在用户登录后才能创建它。问题是数据库创建是异步的,所以它的提供者必须是 FutureProvider。
final databaseFutureProvider = FutureProvider<Database>((ref) {
final authStateChange = ref.watch(_authStateChangesProvider);
final user = authStateChange.data?.value;
if (user != null) {
return FirestoreDatabase.create(user: user);
}
throw UnsupportedError("The database cannot be accessed before the sign-in");
});
这会使整个应用程序的代码更加繁琐。我想将 databaseFutureProvider
设为简单的 Provider
以使应用程序的代码更简洁。怎么做到的?
编辑
最好让数据库创建成为身份验证过程的一部分,这样 authStateChangesProvider
只会在数据库创建后触发。类似于以下内容:
final authStateChangesProvider = FutureProvider<User>((ref) {
final authStateChanged = ref.watch(_authStateChangesProvider);
final user = authStateChanged.data?.value;
if (user != null) {
// await the creation of the database provider
}
return user;
});
这样,只有 authStateChangesProvider
是 FutureProvider。但我是 Riverpod 的新手,我不确定是否以及如何在另一个提供程序中创建一个提供程序。
我想出了一个可能不是最好的解决方案,但我会 post 在这里,以便其他人可以从中受益或希望可以改进它。
我创建了一个新的 ScopedProvider
。
final databaseProvider =
ScopedProvider<Database>((ref) => throw UnimplementedError());
然后我创建了一个新的小部件,它将放置在需要同步访问数据库的小部件树的顶部。此小部件将在创建数据库时仅显示加载视图,然后覆盖 databseProvider
.
class DatabaseWidgetBuilder extends ConsumerWidget {
final Widget Function(Database) childBuilder;
DatabaseWidgetBuilder(
{Key key, @required Widget Function(Database) this.childBuilder})
: super(key: key);
@override
Widget build(BuildContext context, ScopedReader watch) {
final databaseAsyncValue = watch(databaseFutureProvider);
return databaseAsyncValue.when(
data: (database) => ProviderScope(
overrides: [databaseProvider.overrideAs((watch) => database)],
child: childBuilder(database),
),
loading: () => Scaffold(
body: Center(child: CircularProgressIndicator()),
),
error: (_, __) => Scaffold(
body: Center(child: Text("Database Error")),
),
);
}
}
我使用 FirebaseAuth
进行身份验证,并且定义了以下提供程序:
final _authStateChangesProvider = StreamProvider<User>(
(ref) => ref.watch(authServiceProvider).authStateChanges);
数据库依赖于用户,所以我只能在用户登录后才能创建它。问题是数据库创建是异步的,所以它的提供者必须是 FutureProvider。
final databaseFutureProvider = FutureProvider<Database>((ref) {
final authStateChange = ref.watch(_authStateChangesProvider);
final user = authStateChange.data?.value;
if (user != null) {
return FirestoreDatabase.create(user: user);
}
throw UnsupportedError("The database cannot be accessed before the sign-in");
});
这会使整个应用程序的代码更加繁琐。我想将 databaseFutureProvider
设为简单的 Provider
以使应用程序的代码更简洁。怎么做到的?
编辑
最好让数据库创建成为身份验证过程的一部分,这样 authStateChangesProvider
只会在数据库创建后触发。类似于以下内容:
final authStateChangesProvider = FutureProvider<User>((ref) {
final authStateChanged = ref.watch(_authStateChangesProvider);
final user = authStateChanged.data?.value;
if (user != null) {
// await the creation of the database provider
}
return user;
});
这样,只有 authStateChangesProvider
是 FutureProvider。但我是 Riverpod 的新手,我不确定是否以及如何在另一个提供程序中创建一个提供程序。
我想出了一个可能不是最好的解决方案,但我会 post 在这里,以便其他人可以从中受益或希望可以改进它。
我创建了一个新的 ScopedProvider
。
final databaseProvider =
ScopedProvider<Database>((ref) => throw UnimplementedError());
然后我创建了一个新的小部件,它将放置在需要同步访问数据库的小部件树的顶部。此小部件将在创建数据库时仅显示加载视图,然后覆盖 databseProvider
.
class DatabaseWidgetBuilder extends ConsumerWidget {
final Widget Function(Database) childBuilder;
DatabaseWidgetBuilder(
{Key key, @required Widget Function(Database) this.childBuilder})
: super(key: key);
@override
Widget build(BuildContext context, ScopedReader watch) {
final databaseAsyncValue = watch(databaseFutureProvider);
return databaseAsyncValue.when(
data: (database) => ProviderScope(
overrides: [databaseProvider.overrideAs((watch) => database)],
child: childBuilder(database),
),
loading: () => Scaffold(
body: Center(child: CircularProgressIndicator()),
),
error: (_, __) => Scaffold(
body: Center(child: Text("Database Error")),
),
);
}
}