将 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")),
      ),
    );
  }
}