繁体   English   中英

Flutter Riverpod 和 Firebase

[英]Flutter Riverpod and Firebase

我一直在研究一些使用 riverpod 的示例,试图正确地将逻辑与 UI 层和业务层分开。 在这种情况下,我的用例是我想在 Firestore 中存储自定义用户配置文件,但是当涉及 ViewModel 时,我对提供程序设置感到困惑。

来自codewithandrea.com的示例为每个屏幕定义了两个文件,一个 model (ProfileModel) 和一个页面/页面构建器 (ProfilePageBuilder)。 在 ProfilePageBuilder 的顶部,它声明了一个 state 提供程序来访问 ViewModel。 该提供程序解析 ProfileModel 所需的依赖项。

final profileModelProvider =
    StateNotifierProvider.autoDispose<ProfileModel, ProfileState>((ref) {
  final authService = ref.watch(authServiceProvider);

  final databaseService = ref.watch(databaseProvider)!;

  return ProfileModel(
      authService: authService, databaseService: databaseService);
});

现在,我希望页面能够访问从 Firestore 返回的用户配置文件,但 Firestore 服务返回一个Stream<UserProfile> 我的问题是:

  • 我是否将 stream 解析为未来并在调用页面中的方法时返回配置文件,例如 initState 中的 loadProfile()。
  • 或者我是否在链接到 Firestore 服务的 PageBuilder 中创建一个新的 stream 提供程序(我觉得这不符合架构)
  • 我是否从 ViewModel 将 stream 作为 stream 返回,然后创建一个查看 ViewModel 而不是服务的 stream 提供程序?

这是 Firebase 和 Riverpod 的常见问题。

是否要返回 stream 取决于您。 你不必。 这是决定你想要什么的思路。

  • 如果 UI 应该知道“先前”值,您可能应该返回 stream。
  • 如果 UI 只关心“当前”值,则不必返回 stream。
  • 您可以使用有状态小部件跟踪最后一个值,因此您可能只需要当前值。

我将使用带有代码生成语法的 riverpod 2.0,但如果您愿意,这些都可以在没有 codegen 的情况下编写,只是更冗长。

一种方法是使用来自package:rxdart的 BehaviorSubject,它只记住 stream 的最后一个值。

import 'package:rxdart/rxdart.dart';

@riverpod
BehaviorSubject<UserProfile> userProfileSubject(
       UserProfileStreamRef ref, 
       String userId, 
       /*more params if you want*/) {

   final firebaseStream = ...

   // goal of this provider is to get the stream
   // from firebase and convert to a BehaviorSubject
   return BehaviorSubject()
           ..addStream(firebaseStream);
}

@riverpod
UserProfile? userProfile(UserProfileRef ref) {
   // this provider listens to the behavior subject
   // and refreshes itself when the value changes
   // so the dependent providers and widgets can react
   final subject = ref.watch(userProfileSubjectProvider(userId, ...));


   // if no params to provider
   //final subject = ref.watch(userProfileSubjectProvider);

   // when there's a new value, invalidate self
   // so we re-run this and return the new value
   subject.doOnData((newProfile) {ref.invalidateSelf();});

   // note that subject can have a null value until
   // first value is emitted from the stream or stream emits a null.
   // your UI must handle this case.
   return subject.value;
}

现在您的视图 model 或任何可以依赖于此userProfileProvider或直接在ConsumerWidget中使用它的视图。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM