英文:
When the same page displayed in the Drawer is called again, the FutureProvider does not enter the loading state
问题
当您在抽屉中点击一个项目时,它会打开一个名为“FirstPage”的页面。在初始调用时,由于该页面在Widget Tree中不存在,FutureProvider进入加载模式,并且在数据检索后立即切换屏幕。
然而,当显示FirstPage并编写代码从抽屉中调用FirstPage时,FutureProvider的数据检索似乎不会运行,可能是因为FirstPage仍然存在于Widget Tree中并且不会自动解除。
当我尝试在抽屉过渡期间使其失效时,如果FirstPage正在显示,它不会进入加载模式,但数据重新检索会执行。不,我希望它从AsyncValue的加载开始重新开始。
以下是最小可重现示例。我认为从抽屉多次调用相同页面时希望刷新是一个常见的需求,但我想知道其他人都在做什么。
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});
@override
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;
@override
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',
),
],
),
),
);
}
}
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});
@override
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);
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (_) => const FirstPage()));
},
),
],
),
);
}
}
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});
@override
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()));
}
}
import "dart:math";
import 'package:flutter/material.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'sample_provider.g.dart';
@riverpod
Future<String> hello(HelloRef ref) {
return Future<String>.delayed(const Duration(seconds: 2), () {
return "Hello${Random().nextInt(10)}";
});
}
英文:
When you tap an item in the Drawer, it opens a page called "FirstPage". During the initial call, since the page doesn't exist in the Widget Tree, FutureProvider goes into Loading mode, and the screen switches as soon as data is retrieved.
However, when the FirstPage is displayed and you write code to call the FirstPage from the Drawer, FutureProvider's data retrieval doesn't seem to run, perhaps because FirstPage remains in the Widget Tree and doesn't get autoDisposed.
When I tried to invalidate during transition with the Drawer, if FirstPage is displayed, it doesn't go into loading mode, but the data re-retrieval does execute. No, I want it to start over from the loading of AsyncValue.
Below is the Minimal Reproducible Example. I think wanting to Refresh when calling the same page multiple times from the Drawer is a common requirement, but I wonder what everyone else is doing.
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});
@override
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;
@override
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',
),
],
),
),
);
}
}
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});
@override
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);
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (_) => const FirstPage()));
},
),
],
),
);
}
}
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});
@override
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()));
}
}
import "dart:math";
import 'package:flutter/material.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'sample_provider.g.dart';
@riverpod
Future<String> hello(HelloRef ref) {
return Future<String>.delayed(const Duration(seconds: 2), () {
return "Hello${Random().nextInt(10)}";
});
}
答案1
得分: 1
根据Riverpod的文档,当执行刷新操作时,会跳过加载回调。如果您正在使用Riverpod的新版本,您可以将skipLoadingOnRefresh设置为false。
return asyncHello.when(
skipLoadingOnRefresh: false,
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()));
还有第二种方法。您可以通过检查isRefreshing
成员变量来判断是否正在刷新。例如:
@override
Widget build(BuildContext context, WidgetRef ref) {
final asyncHello = ref.watch(helloProvider);
if(asyncHello.isRefreshing) {
// 返回<加载小部件>
}
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()));
}
英文:
According to the documentation of Riverpod, when doing refresh, the loading callback is skipped. If you are using new version of Riverpod, you can make skipLoadingOnRefresh false.
return asyncHello.when(
skipLoadingOnRefresh: false,
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()));
There is second approach. You can check if it is refreshing by checking isRefreshing
member variable. For example:
@override
Widget build(BuildContext context, WidgetRef ref) {
final asyncHello = ref.watch(helloProvider);
if(asyncHello.isRefreshing) {
// return <Loading widget>
}
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()));
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论