Riverpod:是否有在另一个 StreamProvider 中读取 StreamProvider 的正确方法?
Riverpod: Is there a correct way to read a StreamProvider within another StreamProvider?
我一直在尝试使用从我的身份验证 Provider
:
获得的 uid 创建到 Firestore 文档的流
class AuthService {
...
static final provider = StreamProvider.autoDispose((ref) => FirebaseAuth.instance.onAuthStateChanged);
...
}
但是,我正在努力根据来自 auth Provider
的值实际创建 StreamProvider
。
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
到 return uid 或流本身,但是你不能从 [= 中读取 Computed
14=](回想起来是有道理的)。
与此主题最相关,但它处理的是 Provider,而不是 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'))
坚持 login/logout 事件,这可以解释这种行为,但我不确定如何解决它。
有什么想法吗?我已经坚持了一段时间,无法解决这个问题。
问题是,您的提供商没有创建 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);
});
...
}
我想先说我只使用 Dart/Flutter 几个月,所以请随时纠正我所说的任何内容,我会更新答案。
经过反复试验并多次重新审查文档,我解决了这个问题。我想我做了一个错误的假设,即当 Provider 依赖更改时 Provider 会更新。
我发现一旦 StreamProvider returns(或 yields),在它被处置之前它总是 return 它最初的相同值,无论依赖性变化或事件来自溪流。这是 Computed 有用的地方,但当您希望 return 来自提供商的 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 在用户退出您的应用程序时不再依赖提供商(允许他们被妥善处理),则此解决方案有效。
我一直在尝试使用从我的身份验证 Provider
:
class AuthService {
...
static final provider = StreamProvider.autoDispose((ref) => FirebaseAuth.instance.onAuthStateChanged);
...
}
但是,我正在努力根据来自 auth Provider
的值实际创建 StreamProvider
。
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
到 return uid 或流本身,但是你不能从 [= 中读取 Computed
14=](回想起来是有道理的)。
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'))
坚持 login/logout 事件,这可以解释这种行为,但我不确定如何解决它。
有什么想法吗?我已经坚持了一段时间,无法解决这个问题。
问题是,您的提供商没有创建 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);
});
...
}
我想先说我只使用 Dart/Flutter 几个月,所以请随时纠正我所说的任何内容,我会更新答案。
经过反复试验并多次重新审查文档,我解决了这个问题。我想我做了一个错误的假设,即当 Provider 依赖更改时 Provider 会更新。
我发现一旦 StreamProvider returns(或 yields),在它被处置之前它总是 return 它最初的相同值,无论依赖性变化或事件来自溪流。这是 Computed 有用的地方,但当您希望 return 来自提供商的 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 在用户退出您的应用程序时不再依赖提供商(允许他们被妥善处理),则此解决方案有效。