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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 00:12:18