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

AsyncNotifierProvider与AsyncNotifier正确用法及多Provider组合问题

AsyncNotifierProvider 用法修正与多Provider组合方案

一、你代码里的核心问题

  • 别在AsyncNotifier的构造函数里调用getCards()!这时候ref还没初始化,直接用肯定报错
  • 拿其他Provider数据的方式错了:await ref.watch(pendingProvider)不行,ref.watch返回的是AsyncValue,得用.future属性拿对应的Future才能await
  • 组件加载时没正确触发数据获取逻辑

二、修正后的完整代码

1. 先把两个基础Provider改对

让它们在build时自动加载数据,不用手动调方法(如果需要重新加载可以保留方法):

final pendingProvider = AsyncNotifierProvider<PendingProvider, List<Base>>(PendingProvider.new);

class PendingProvider extends AsyncNotifier<List<Base>> {
  final Repository repository = Repository();

  @override
  FutureOr<List<Base>> build() {
    // 初始化时自动加载待处理数据
    return AsyncValue.guard(() => repository.getPending());
  }

  // 要重新加载就调这个方法(可选)
  Future<void> refreshPending() async {
    state = await AsyncValue.guard(() => repository.getPending());
  }
}
final lastTrialProvider = AsyncNotifierProvider<LastTrialProvider, Trial?>(LastTrialProvider.new);

class LastTrialProvider extends AsyncNotifier<Trial?> {
  final Repository repository = Repository();

  @override
  FutureOr<Trial?> build() {
    // 初始化时自动加载最新试训数据
    return AsyncValue.guard(() => repository.getLastTrial()); // 假设你repo里有这个方法
  }

  // 重新加载最新试训数据(可选)
  Future<void> refreshLastTrial() async {
    state = await AsyncValue.guard(() => repository.getLastTrial());
  }
}

2. 实现多Provider并行加载的IndependentCardProvider

用Future.wait同时等两个Provider的数据,和你想要的效果一样:

final independentCardProvider = AsyncNotifierProvider<IndependentCardProvider, List<EventModel>>(IndependentCardProvider.new);

class IndependentCardProvider extends AsyncNotifier<List<EventModel>> {
  @override
  List<EventModel> build() {
    // 初始返回空列表
    return [];
  }

  Future<void> getCards() async {
    // 并行等待两个Provider的数据加载完成
    final [pendingData, lastTrialData] = await Future.wait([
      ref.watch(pendingProvider.future),
      ref.watch(lastTrialProvider.future),
    ]);

    // 这里写你的业务逻辑,比如把两个数据合并成EventModel列表
    final eventList = <EventModel>[];

    // 示例:添加一个测试事件
    final sectionModel = EventModel();
    sectionModel.title = 'add';
    sectionModel.subTitle = 'add_to_schedule';
    eventList.add(sectionModel);

    // 更新状态,UI会自动刷新
    state = AsyncValue.data(eventList);
  }
}

3. 组件加载时触发getCards方法

在组件的initState里调用,注意用addPostFrameCallback确保组件挂载后再执行:

class IndependentCardListState extends ConsumerState<IndependentCardList> {
  @override
  void initState() {
    super.initState();
    // 组件渲染完成后调用getCards加载数据
    WidgetsBinding.instance.addPostFrameCallback((_) {
      ref.read(independentCardProvider.notifier).getCards();
    });
  }

  @override
  Widget build(BuildContext context) {
    final cardState = ref.watch(independentCardProvider);

    // 根据状态渲染不同UI
    return cardState.when(
      loading: () => const Center(child: CircularProgressIndicator()),
      error: (err, stack) => Center(child: Text('加载炸了: $err')),
      data: (cards) {
        return ListView.builder(
          itemCount: cards.length,
          itemBuilder: (context, index) {
            final card = cards[index];
            return ListTile(
              title: Text(card.title),
              subtitle: Text(card.subTitle),
            );
          },
        );
      },
    );
  }
}

三、重点要注意的点

  • ref的使用时机:AsyncNotifier的ref只有在build方法执行后才可用,绝对不能在构造函数里调用依赖ref的方法
  • 多Provider组合:想要并行加载就用Future.wait,每个Provider通过.future拿到对应的Future就行,和普通Future组合逻辑完全一样
  • 组件触发方法:用ref.read拿notifier(因为只调一次,不用监听变化),放在addPostFrameCallback里避免组件还没挂载就执行
  • 状态更新要规范:用AsyncValue.guard或者直接赋值AsyncValue.data/error,这样UI层才能用when轻松处理加载、错误、成功三种状态

内容的提问来源于stack exchange,提问作者hemant

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 08:17:04