使用select方法时如何保留AsyncValue的加载与错误状态?
解决方法
要在保留AsyncValue加载/错误状态的同时,只监听子模型变化,核心是让select返回的仍然是AsyncValue类型,而不是直接提取内部数据。下面是两种可行方案:
方案一:直接在select中转换AsyncValue
不用直接提取value?.mainProductModel,而是通过AsyncValue.map将原状态转换成仅包含目标子模型的AsyncValue,这样既保留了加载、错误状态,又只会在子模型变化时触发Widget重建:
var mainProductState = ref.watch( mainProductNewProvider(widget.mainProductId).select((asyncState) { return asyncState.map( data: (dataState) => AsyncValue.data(dataState.value.mainProductModel), loading: (_) => const AsyncValue.loading(), error: (errorState) => AsyncValue.error(errorState.error, errorState.stackTrace), ); }), );
之后你可以像处理普通AsyncValue一样用when方法处理状态:
mainProductState.when( loading: () => const CircularProgressIndicator(), error: (err, stack) => Text('出错了: $err'), data: (mainProductModel) => Text(mainProductModel?.name ?? '无数据'), );
如果其他Widget需要监听MainProductStateModel里的其他子模型,比如otherSubModel,只需要复制这个逻辑,替换成对应的子模型即可,彼此之间的重建互不影响。
方案二:拆分出子Provider(更整洁)
如果多个Widget需要复用同一个子模型的监听逻辑,可以单独封装一个子Provider,依赖主Provider并做select转换:
@riverpod AsyncValue<MainProductModel?> mainProductModel(MainProductModelRef ref, String productId) { return ref.watch( mainProductNewProvider(productId).select((asyncState) { return asyncState.map( data: (d) => AsyncValue.data(d.value.mainProductModel), loading: (_) => const AsyncValue.loading(), error: (e) => AsyncValue.error(e.error, e.stackTrace), ); }), ); } // 同理,监听其他子模型的Provider @riverpod AsyncValue<OtherSubModel?> otherSubModel(OtherSubModelRef ref, String productId) { return ref.watch( mainProductNewProvider(productId).select((asyncState) { return asyncState.map( data: (d) => AsyncValue.data(d.value.otherSubModel), loading: (_) => const AsyncValue.loading(), error: (e) => AsyncValue.error(e.error, e.stackTrace), ); }), ); }
之后Widget只需要监听对应的子Provider即可:
var mainProductState = ref.watch(mainProductModelProvider(widget.mainProductId));
这种方式的好处是把转换逻辑抽离出来,避免重复代码,多个Widget复用更方便。
内容的提问来源于stack exchange,提问作者Cyrus the Great
相关产品推荐
相关产品推荐

