You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何已有值时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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 19:35:30