4

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

class AuthService {
  ...

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

但是,我正在努力实际创建一个StreamProvider依赖于 auth 的值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从 a中读取 a Provider(回想起来这很有意义)。

这个问题与这个主题最相关,但它涉及的是 Provider,而不是 Riverpod。

PS 可以创建 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的地方也会更新流,但是在任何更多的身份验证事件中,只有侦听器被触发并且没有事件被await for loop.

有趣的是,使用颤振检查器,auth 提供者发出的值也永远不会改变:

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

通过登录/注销事件持续存在,这可以解释这种行为,但我不确定如何修复它。

有任何想法吗?我已经坚持了一段时间,无法纠正这个问题。

4

2 回答 2

8

问题是,您的提供者不会创建一个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);
  });
  ...
}
于 2020-07-14T19:35:21.033 回答
1

我想先说我只使用 Dart/Flutter 几个月,所以请随时纠正我所说的任何内容,我会更新答案。

经过多次试验和错误并多次重新审查文档后,我解决了这个问题。我想我做了一个糟糕的假设,即当他们依赖的 Provider 发生变化时,Providers 会更新。

我发现一旦 StreamProvider 返回(或产生),直到它被释放,它总是返回它最初所做的相同值,而不管依赖项更改或来自 Stream 的事件。这是 Computed 有用的地方,但当您希望从您的提供者返回 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 不再依赖于提供程序(允许正确处理它们),此解决方案有效。

于 2020-07-16T22:49:52.713 回答