在不显示加载程序的情况下刷新 FutureProvider
Refresh FutureProvider without showing loader
我有一个钱包提供商,它使用未来提供商从服务器获取钱包余额,一切正常,我遇到的唯一问题是刷新钱包提供商以使用 context.refresh(walletProvider)。这很好用,但我不希望加载小部件在它尝试从服务器获取新数据时显示,而是应该显示旧数据,直到新数据从服务器返回。
代码如下:
final walletProvider =
FutureProvider<WalletModel>((ref) => WalletService().fetchWalletBalance());
Consumer(builder: (context, watch, child) {
final wallet = watch(walletProvider);
return Column(
children: [
wallet.when(
data: (value) {
return walletContainer(
context: context, walletModel: value);
},
loading: () => walletLoading(),
error: (err, stack) {
return Text(
'${err.toString()}',
},
)
],
),
然后我从一个按钮调用 context.refresh(walletProvider);
,它刷新但显示加载程序小部件,这不是我想要的。我希望在刷新过程中显示之前的数据。
请问如何实现这个?
将来可能会有更好的解决方案 (see this issue)。
不过,与此同时,我想出了一个应该会产生您想要的行为的解决方案。
final myFutureProvider = FutureProvider.autoDispose<List<int>>((ref) async {
return Future.delayed(
const Duration(seconds: 2),
() => List<int>.generate(100, (_) => Random().nextInt(1000)),
);
});
final cachedProvider = StateProvider.autoDispose<List<int>>((ref) => []);
class ExampleListView extends StatelessWidget {
const ExampleListView({Key? key, required this.data}) : super(key: key);
final List<int> data;
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) => ListTile(title: Text(data[index].toString())),
);
}
}
class Refresher extends ConsumerWidget {
const Refresher({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, ScopedReader watch) {
return RefreshIndicator(
onRefresh: () async {
await context.refresh(myFutureProvider);
},
child: watch(myFutureProvider).when(
loading: () {
final cachedData = watch(cachedProvider).state;
return cachedData.isNotEmpty
? ExampleListView(data: cachedData)
: Center(child: CircularProgressIndicator());
},
error: (e, s) => Text(''),
data: (data) {
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
watch(cachedProvider).state = data;
});
return ExampleListView(data: data);
},
),
);
}
}
本质上,我们将以前的数据保存到 StateProvider 中,以便我们可以在加载新数据时继续显示以前的数据。我将此示例设为通用示例,因此它处于准备就绪状态,您可以在将其应用到您的代码之前进行试用。
我有一个钱包提供商,它使用未来提供商从服务器获取钱包余额,一切正常,我遇到的唯一问题是刷新钱包提供商以使用 context.refresh(walletProvider)。这很好用,但我不希望加载小部件在它尝试从服务器获取新数据时显示,而是应该显示旧数据,直到新数据从服务器返回。
代码如下:
final walletProvider =
FutureProvider<WalletModel>((ref) => WalletService().fetchWalletBalance());
Consumer(builder: (context, watch, child) {
final wallet = watch(walletProvider);
return Column(
children: [
wallet.when(
data: (value) {
return walletContainer(
context: context, walletModel: value);
},
loading: () => walletLoading(),
error: (err, stack) {
return Text(
'${err.toString()}',
},
)
],
),
然后我从一个按钮调用 context.refresh(walletProvider);
,它刷新但显示加载程序小部件,这不是我想要的。我希望在刷新过程中显示之前的数据。
请问如何实现这个?
将来可能会有更好的解决方案 (see this issue)。
不过,与此同时,我想出了一个应该会产生您想要的行为的解决方案。
final myFutureProvider = FutureProvider.autoDispose<List<int>>((ref) async {
return Future.delayed(
const Duration(seconds: 2),
() => List<int>.generate(100, (_) => Random().nextInt(1000)),
);
});
final cachedProvider = StateProvider.autoDispose<List<int>>((ref) => []);
class ExampleListView extends StatelessWidget {
const ExampleListView({Key? key, required this.data}) : super(key: key);
final List<int> data;
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) => ListTile(title: Text(data[index].toString())),
);
}
}
class Refresher extends ConsumerWidget {
const Refresher({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, ScopedReader watch) {
return RefreshIndicator(
onRefresh: () async {
await context.refresh(myFutureProvider);
},
child: watch(myFutureProvider).when(
loading: () {
final cachedData = watch(cachedProvider).state;
return cachedData.isNotEmpty
? ExampleListView(data: cachedData)
: Center(child: CircularProgressIndicator());
},
error: (e, s) => Text(''),
data: (data) {
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
watch(cachedProvider).state = data;
});
return ExampleListView(data: data);
},
),
);
}
}
本质上,我们将以前的数据保存到 StateProvider 中,以便我们可以在加载新数据时继续显示以前的数据。我将此示例设为通用示例,因此它处于准备就绪状态,您可以在将其应用到您的代码之前进行试用。