Dart Rx 删除等待

Dart Rx remove await

我正在学习rx/dart。但我很挣扎。有什么方法可以使 属性 同步吗? await currentUser() 迫使我做 属性 async。但我需要某种技巧,因为我无法更改界面的这一部分。而且我不想使用适配器模式。

属性应该returnStream<User>。有什么办法可以达到这个目的吗?

Future<Stream<User>> get onUserOrAuthStateChanged async {
    return authentication.onAuthStateChanged
        .asyncMap<User>((authenticationUser) async {
      return await _retrieveUserFromAuthenticationUser(authenticationUser);
    }).concatWith([
      await currentUser() == null
          ? Stream.empty()
          : userRepository.getStream((await currentUser()).id).skip(1)
    ]);
  }

编辑: 也可以使用 authenticationUser 代替 await currentUser()。像这样:

Stream<User> get onUserOrAuthStateChanged {
        AuthenticationUser currentAuthenticationUser;
        return authentication.onAuthStateChanged
            .asyncMap<User>((authenticationUser) async {
          currentAuthenticationUser = authenticationUser;
          return await _retrieveUserFromAuthenticationUser(authenticationUser);
        }).concatWith([
          currentAuthenticationUser == null
              ? Stream.empty()
              : userRepository.getStream(currentAuthenticationUser.uid).skip(1)
        ]);
      }

通过这种方法,我摆脱了异步,但是在执行 concatWith 方法时 currentAuthenticationUser 总是 null,因为在 concatWith currentAuthenticationUser = authenticationUser;

您可以使用 Stream.fromFuture()Future 转换为 Stream

这些是一些伪代码选项,因为我不完全了解你的代码,我也没有尝试编译它,只是凭记忆在这里输入。

: userRepository.getStream((Stream.fromFuture(await currentUser())).id).skip(1)

: userRepository.getStream((Stream.fromFuture(currentUser().map((u) => u.id)))).skip(1)

这是我想出的解决方案:

Stream<User> get onUserOrAuthStateChanged {
    return authentication.onAuthStateChanged.switchMap((authenticationUser) =>
        authenticationUser == null
            ? Stream.value(null)
            : userRepository.getStream(authenticationUser.uid));
  }

或者,您可以使用新的 await for 语法代替 RxDart:

Stream<UserProfile> get user$ async* {
  await for (final currentUser in _firebaseAuth.onAuthStateChanged) {
    if (currentUser != null) {
      await for (final user in getUserStreamFromId(currentUser.uid)) {
        yield UserProfile.fromFirestore(user);
      }
    }
  }
}

我认为 await forswitchMap 一样工作,我创建了一个 gist 来测试它。

如果您需要最新值,可以让 Provider 为您管理缓存。

...
StreamProvider(
  create: (context) => userRepo.user$,
),
...

这是 Flutter 的做法。然后很容易在 children:

中访问它
final user = context.watch<UserProfile>();
...

更新

切换可能是个更好的主意,因为飞镖 await for API 改为绘制排气图:

  Stream<UserProfile> get user$ {
    return _firebaseAuth.onAuthStateChanged.switchMap((currentUser) async* {
      if (currentUser != null) {
        await for (final user in getUserStreamFromId(currentUser.uid)) {
          yield UserProfile.fromFirestore(user);
        }
      } else {
        yield null;
      }
    });
  }