如何在Flutter中使用Riverpod刷新FutureProvider时避免再次显示加载指示器?

8

目前,我正在刷新一个FutureProvider,负责从Firebase获取数据并使用liquid_pull_to_refresh包在简单的ListView中显示它,这会导致列表消失,再次显示加载指示器,最后再次显示列表。

相反,我希望保持列表显示,并在获取完成后仅更新它。我正在使用Riverpod进行状态管理。

提供程序:

final userProfileProvider = FutureProvider.family<FullUserModel?, String?>((ref, value) => ref.read(databaseServiceProvider).getFullUserModel(value));

刷新部分:

LiquidPullToRefresh(
  onRefresh: () async {
    ref.refresh(userProfileProvider(uid));
  },
  child: ListView()
)

有没有好的方法来解决这个问题?

2个回答

9
这已经不再是一个问题,因为Riverpod 2.0+具有新的刷新行为。现在,在加载时它会返回先前的数据/错误值。

当提供者发出AsyncValue.data或AsyncValue.error后,该提供者将不再发出AsyncValue.loading。 相反,它将重新发出最新的值,但属性AsyncValue.isRefreshing为true。

这使得UI能够在提供者正在刷新时继续显示先前的数据/错误。

如果您希望在数据刷新时选择性地显示加载指示器或其他元素,只需查找AsyncValue.isRefreshing的布尔值即可。

来源


如何在加载时显示进度对话框? - NELSON RODRIGUEZ
如果你在谈论初始加载,那么你可以简单地使用.when语法来处理错误、加载和数据状态。如果你在谈论重新加载(即在提供程序已经发出AsyncValue.data或AsyncValue.error之后发生的加载),你可以选择在AsyncValue.isRefreshing==true时显示进度对话框。 - Muhammad Vaid

1

我不确定这是否是一个好的方法,但我已经制作了一个示例来实现这个目标:

小部件:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          body: Center(
        child: TimeDisplayer(),
      )),
    );
  }
}

class TimeDisplayer extends ConsumerWidget{
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final time = ref.watch(ref.watch(diplayedTimer));

    return Column(
      children: [
        time.when(data: (data)=>Text(data.toString()), error: (e,_)=>Text(e.toString()), loading: ()=>CircularProgressIndicator()),
        IconButton(onPressed: ()=>ref.refresh(timeRefreshProvider), icon: Icon(Icons.refresh))
      ],
    );
  }
}

提供者:

final timeRefreshProvider = FutureProvider<DateTime>((ref) async {
  await Future.delayed(const Duration(seconds: 1));
  return DateTime.now();
});

final diplayedTimer = Provider<StateProvider<AsyncValue<DateTime>>>((ref) {
  final _diplayedTimer = StateProvider<AsyncValue<DateTime>>((ref) {
    return const AsyncLoading();
  });
  ref.listen(timeRefreshProvider, (previous, next) {
    if (next is AsyncData<DateTime>) {
      ref.read(_diplayedTimer.state).update((state) => next);
    }
  });
  return _diplayedTimer;
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接