当再次调用在抽屉中显示的同一页时,FutureProvider 不会进入加载状态。

huangapple go评论63阅读模式
英文:

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 &#39;package:drawer_refresh_sample/drawer.dart&#39;;
import &#39;package:flutter/material.dart&#39;;
import &#39;package:hooks_riverpod/hooks_riverpod.dart&#39;;

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: &#39;Flutter Demo&#39;,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: &#39;Flutter Demo Home Page&#39;),
    );
  }
}

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: &lt;Widget&gt;[
            Text(
              &#39;Good Morning&#39;,
            ),
          ],
        ),
      ),
    );
  }
}
import &#39;package:drawer_refresh_sample/first_page.dart&#39;;
import &#39;package:flutter/material.dart&#39;;
import &#39;package:hooks_riverpod/hooks_riverpod.dart&#39;;

class SampleDrawer extends ConsumerWidget {
  const SampleDrawer({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Drawer(
      child: ListView(
        children: &lt;Widget&gt;[
          ListTile(
            title: const Text(&quot;Page 1&quot;),
            trailing: const Icon(Icons.arrow_forward),
            onTap: () {
              Navigator.of(context).pop();
              ref.invalidate(helloProvider);
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (_) =&gt; const FirstPage()));
            },
          ),
        ],
      ),
    );
  }
}
import &#39;package:drawer_refresh_sample/sample_provider.dart&#39;;
import &#39;package:flutter/material.dart&#39;;
import &#39;package:hooks_riverpod/hooks_riverpod.dart&#39;;

import &#39;drawer.dart&#39;;

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) =&gt; Scaffold(
            appBar: AppBar(
              title: const Text(&quot;First Page&quot;),
            ),
            drawer: const SampleDrawer(),
            body: SafeArea(child: Center(child: Text(data)))),
        error: (error, stackTrace) =&gt; Text(stackTrace.toString()),
        loading: () =&gt; const Center(child: CircularProgressIndicator.adaptive()));
  }
}
import &quot;dart:math&quot;;

import &#39;package:flutter/material.dart&#39;;
import &#39;package:riverpod_annotation/riverpod_annotation.dart&#39;;

part &#39;sample_provider.g.dart&#39;;

@riverpod
Future&lt;String&gt; hello(HelloRef ref) {
  return Future&lt;String&gt;.delayed(const Duration(seconds: 2), () {
    return &quot;Hello${Random().nextInt(10)}&quot;;
  });
}

答案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) =&gt; Scaffold(
            appBar: AppBar(
              title: const Text(&quot;First Page&quot;),
            ),
            drawer: const SampleDrawer(),
            body: SafeArea(child: Center(child: Text(data)))),
        error: (error, stackTrace) =&gt; Text(stackTrace.toString()),
        loading: () =&gt; 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 &lt;Loading widget&gt;
    }
    return asyncHello.when(
        data: (data) =&gt; Scaffold(
            appBar: AppBar(
              title: const Text(&quot;First Page&quot;),
            ),
            drawer: const SampleDrawer(),
            body: SafeArea(child: Center(child: Text(data)))),
        error: (error, stackTrace) =&gt; Text(stackTrace.toString()),
        loading: () =&gt; const Center(child: CircularProgressIndicator.adaptive()));
  }

huangapple
  • 本文由 发表于 2023年6月29日 22:13:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76581889.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定