Riverpod:是否存在在另一个StreamProvider中读取StreamProvider的正确方法?

时间:2020-07-14 17:15:40

标签: flutter dart riverpod

我一直在尝试使用从我的认证Provider获得的 uid 创建流到Firestore文档的流:

class AuthService {
  ...

  static final provider = StreamProvider.autoDispose((ref) => FirebaseAuth.instance.onAuthStateChanged);
  ...
}

但是,我正努力根据auth StreamProvider中的值来创建一个Provider

class User {
  ...
  static final provider = StreamProvider((ref) {
    final stream = ref.read(AuthService.provider);
    // Returns AsyncValue<Stream<User>> instead of desired AsyncValue<User>
    return stream.map((auth) => Service.user.stream(auth.uid));
  });
  ...
}

我还尝试使用Computed返回 uid 或流本身,但是您无法从Computed读取Provider(回想起来很有意义)。

This question是与此主题最相关的内容,但它与提供者(而不是Riverpod)打交道。

P.S。可以创建Riverpod标签吗?

编辑:

答案不太正确。 await for loop仅触发一次,而侦听器捕获所有事件。

static final provider = StreamProvider((ref) async* {
  final stream = ref.read(AuthService.provider);
  print('userProvider init');

  stream.listen((auth) {
    print('LISTENED: ${auth?.uid}');
  });

  await for (final auth in stream) {
    print('uid: ${auth?.uid}');
    yield* Service.user.stream(auth?.uid);
  }
});

此代码在登录时会产生以下内容:

userProvider init
LISTENED: <redacted UID>
uid: <redacted UID>

然后注销:

LISTENED: null

我也希望看到uid: null,它将更新流,但是在发生更多的auth事件时,仅触发侦听器,而await for loop不会捕获任何事件。

有趣的是,使用flutter检查器,auth提供程序发出的值永远不会更改,

AutoDisposeStreamProvider<FirebaseUser>#95f11: AsyncValue<FirebaseUser>.data(value: FirebaseUser(Instance of 'PlatformUser'))

通过登录/注销事件持续存在,这可以解释这种现象,但是我不确定该如何解决。

有什么想法吗?我已经坚持了一段时间,无法解决问题。

2 个答案:

答案 0 :(得分:4)

问题是,您的提供商没有创建Stream<User>,而是创建Stream<Stream<User>>

作为0.6.0-dev的一部分,您可以使用ref.watch轻松组合流:

class User {
  ...
  static final provider = StreamProvider((ref) {
    final auth = ref.watch(AuthService.provider);
    return Service.user.stream(auth.uid);
  });
  ...
}

答案 1 :(得分:1)

我想通过说我只与Dart / Flutter一起工作了几个月来对此做个开头,所以请随时纠正我说的任何内容,然后我将更新答案。

经过反复尝试和多次重新审查文档,我解决了此问题。我猜我有一个很糟糕的假设,即当提供商依赖于更改时提供商会更新。

我发现,一旦StreamProvider返回(或让步),直到处置掉它,它总是将返回与原始值相同的值,而不管依赖关系更改或来自Stream的事件如何。在这里,“计算”很有用,但是当您希望从提供程序返回AsyncValue时(StreamProvider的行为),它实际上并不能很好地工作。

此外,由于Flutter Inspector无法正确更新ProviderScope小部件而引起了其他混乱。我必须单击并刷新几次才能查看对提供程序或其状态的更新。反正...

class AuthService {
  ...
  static final provider = StreamProvider.autoDispose((ref) {
    final sub = FirebaseAuth.instance.onAuthStateChanged.listen((auth) => ref.read(uidProvider).state = auth?.uid);
    ref.onDispose(() => sub.cancel());
    return FirebaseAuth.instance.onAuthStateChanged;
  });

  static final uidProvider = StateProvider<String>((_) => null);
  ...
}
class User {
  ...
  static final provider = StreamProvider.autoDispose((ref) {
    final uid = ref.read(AuthService.uidProvider)?.state;
    return Service.user.stream(uid);
  });
  ...

鉴于用户退出应用程序后您的UI不再依赖提供程序(允许它们正确处置),此解决方案有效。