为何已有值时Riverpod Provider仍进入加载状态?
Riverpod StreamProvider 加载状态与值的疑问解析
最小可复现代码
class FooPage extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final asyncValue = ref.watch(provider1); print('loading: ${asyncValue.isLoading}, value: ${asyncValue.valueOrNull}'); return Container(); } } final provider1 = StreamProvider<int>((ref) { final stream = ref.watch(provider2); return stream.maybeWhen( orElse: () => Stream.value(0), data: (x) { print('data = $x'); return Stream.value(x); }, ); }); final provider2 = StreamProvider<int>((ref) async* { await Future.delayed(Duration(seconds: 3)); yield 1; });
输出结果
flutter: loading: true, value: null // 为何value不等于0 flutter: loading: false, value: 0 // 3秒后... flutter: data = 1 flutter: loading: true, value: 0 // 为何value不等于1 flutter: loading: false, value: 1
疑问解答
1. 已在orElse提供默认值0,为何第一行输出仍为加载状态且value为null?
provider2初始状态是AsyncLoading,此时ref.watch(provider2)拿到的是加载状态的AsyncValue,触发maybeWhen的orElse回调,返回Stream.value(0)。但provider1作为StreamProvider,需要订阅这个新返回的Stream,在订阅后到Stream发出第一个值(0)的这段时间里,provider1自身的状态是AsyncLoading,所以asyncValue.isLoading为true,valueOrNull为null。只有当Stream成功发出0后,provider1的状态才会切换为AsyncData,此时value才会变为0。
2. 3秒后获取数据时,为何输出loading: true, value: 0而非直接显示新值1?
3秒后provider2发出数据1,此时ref.watch(provider2)拿到的是AsyncData(1),触发maybeWhen的data回调,返回Stream.value(1)。provider1会取消之前的Stream订阅,转而订阅这个新的Stream。在切换订阅到新Stream发出值1的这段时间里,provider1的状态会先变为AsyncLoading,但它会保留上一次的有效值0(Riverpod在加载新数据时会暂存旧值),所以valueOrNull是0。等新Stream发出1后,provider1的状态切换为AsyncData,value才会更新为1。
内容的提问来源于stack exchange,提问作者iDecode
相关产品推荐
相关产品推荐

