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
相关产品推荐
相关产品推荐

