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

Riverpod FutureProvider.family传参后无法正常刷新问题求助

Riverpod Family FutureProvider 传非空参数时列表不刷新问题排查

问题描述

我开发了一个测试Widget,用FakeApi生成员工列表。向futureApiProvider2传递空参数时,列表能正常显示并更新;但传递非空参数时,虽然getData方法已被调用(控制台能打印输出),但列表完全不刷新。

相关代码

FakeApiRepo类

class FakeApiRepo{
    Future<List<Worker>> getData({required String someText})async{
      List<String> names = ["Arkadiusz",
        "Arkady",
        "Arnold",
        ];
      List<String> surnames = [ "Piskorski",
        "Borowy",
        "Kołek",
        ];
      List<int> ages = [12,14,15,16,17,33,44,55,66,77,88,99];

      Random rnd = Random();
      int count = rnd.nextInt(20);
      List<Worker> list = [];

      for(var i = 0; i < count; i++ ){
        list.add(
          Worker(name: names[rnd.nextInt(names.length)],
              surname: surnames[rnd.nextInt(surnames.length)],
              age: ages[rnd.nextInt(ages.length)], text: someText)
        );
      }
      await Future.delayed(const Duration(seconds: 5));
      print('There you go: ${count}');
      return list;
    }
  }

Provider定义

final fakeApiProvider = Provider<FakeApiRepo>((ref){
  return FakeApiRepo();
});

final futureApiProvider2 = FutureProvider.autoDispose.family<List<Worker>, CustomParams>((ref, params){
  return ref.watch(fakeApiProvider).getData(someText: params.text);
});

CustomParams类

class CustomParams extends Equatable{
  const CustomParams({required this.text});
  final String text;

  @override
  List<Object> get props => [text];
}

测试Widget代码

Column(
  children: [
    TextButton(onPressed: (){
      ref.refresh(
          futureApiProvider2(
              CustomParams(
                  text: Random().nextInt(100).toString() // 移除该参数(text为空)时列表会重新生成
              )
          )
      );
    }, child: const Text('UPDATE')),
    data.when(
        data: (positions){
          return ListView.builder(
            shrinkWrap: true,
            itemCount: positions.length,
            itemBuilder: (context, index){
              return ListTile(
                title: Text("${positions[index].name} ${positions[index].surname}"),
                subtitle: Text("Age: ${positions[index].age} -- ${positions[index].text}"),
              );
            },
          );
        },
        error: (e, st) => const Center(child: Text('Some error'),),
        loading: () => const CircularProgressIndicator()
    )
  ],
),

问题排查与解决

核心问题是Widget监听的Provider实例和你refresh的实例不一致:当传递不同的非空CustomParams时,你创建了新的futureApiProvider2实例,但Widget仍在监听旧参数对应的Provider实例,导致新数据无法更新到界面。

解决步骤

  1. 用StateProvider管理当前参数
    新增一个StateProvider来保存当前使用的CustomParams,让Widget跟随参数变化自动切换监听的Provider实例:

    final currentParamsProvider = StateProvider<CustomParams>((ref) => const CustomParams(text: ""));
    
  2. 修改Widget监听逻辑
    在Widget中先获取当前参数,再监听对应Provider的状态:

    final currentParams = ref.watch(currentParamsProvider);
    final data = ref.watch(futureApiProvider2(currentParams));
    
  3. 调整按钮点击逻辑
    点击按钮时更新参数状态,并刷新对应Provider:

    TextButton(onPressed: (){
      final newParams = CustomParams(text: Random().nextInt(100).toString());
      ref.read(currentParamsProvider.notifier).state = newParams;
      ref.refresh(futureApiProvider2(newParams));
    }, child: const Text('UPDATE')),
    
  4. 验证Equatable实现
    你的CustomParams已经正确继承Equatable并实现props,这部分没问题,Riverpod能正确区分不同参数的Provider实例。

这样修改后,Widget会始终监听当前参数对应的Provider实例,refresh后新数据就能正常更新到列表了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 10:20:31