🙄
【解決】Drawerで表示されているページを再度呼び出すとFutureProviderがloadingにならない
どうしたもんかなと思っています。
Drawerのアイテムをタップして、FirstPage
というページを出します。初回呼び出しの時は、Widget Treeにそのページがないので、FutureProviderがLoadingになり、dataが取得できると画面が切り替わります。
ただ、FirstPage
が表示されている状態で、DrawerよりFirstPage
を呼び出すコードを書くと、Widget TreeにFirstPage
が残ってしまうためかautoDispose
されないようで、FutureProviderのデータ再取得が走らない。
Drawerで遷移する時にinvalidate
してみると、FirstPage
が表示されている場合、loadingにはならないが、データの再取得は実行された。いやいや、AsyncValueのloadingからやり直してほしいんです!
以下が Minimal Reproducible Exampleです。
Drawerで同じページを何度も呼び出す時にRefreshしたいは結構ある要件だと思うけど、みんなどうしているんだろうか。
追記
skipLoadingOnRefresh: false
で解決しました・・・ ドキュメントはちゃんと読もう。AsyncValueの。
main.dart
import 'package:drawer_refresh_sample/drawer.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key, required this.title});
final String title;
Widget build(BuildContext context) {
return Scaffold(
drawer: const SampleDrawer(),
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(title),
),
body: const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Good Morning',
),
],
),
),
);
}
}
drawer.dart
import 'package:drawer_refresh_sample/first_page.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
class SampleDrawer extends ConsumerWidget {
const SampleDrawer({super.key});
Widget build(BuildContext context, WidgetRef ref) {
return Drawer(
child: ListView(
children: <Widget>[
ListTile(
title: const Text("Page 1"),
trailing: const Icon(Icons.arrow_forward),
onTap: () {
Navigator.of(context).pop();
ref.invalidate(helloProvider);
// 以下でも現象は同じ
// ref.refresh(helloProvider.future);
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (_) => const FirstPage()));
},
),
],
),
);
}
}
first_page.dart
import 'package:drawer_refresh_sample/sample_provider.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'drawer.dart';
class FirstPage extends ConsumerWidget {
const FirstPage({super.key});
Widget build(BuildContext context, WidgetRef ref) {
final asyncHello = ref.watch(helloProvider);
return asyncHello.when(
data: (data) => Scaffold(
appBar: AppBar(
title: const Text("First Page"),
),
drawer: const SampleDrawer(),
body: SafeArea(child: Center(child: Text(data)))),
error: (error, stackTrace) => Text(stackTrace.toString()),
loading: () => const Center(child: CircularProgressIndicator.adaptive()));
}
}
sample_provider.dart
import "dart:math";
import 'package:flutter/material.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'sample_provider.g.dart';
Future<String> hello(HelloRef ref) {
return Future<String>.delayed(const Duration(seconds: 2), () {
return "Hello${Random().nextInt(10)}";
});
}
Discussion