如何根据riverpods streamProvider 更新嵌套屏幕?

Posted

技术标签:

【中文标题】如何根据riverpods streamProvider 更新嵌套屏幕?【英文标题】:How to update nested screens based on riverpods streamProvider? 【发布时间】:2021-07-02 07:26:31 【问题描述】:

假设有三个屏幕。 main.dart、home.dart 和 signIn.dart 我有代码,如下所示。当我在主屏幕中并且 streamProvider(firebaseAuthStateProvider) 发生变化时,我将自动返回 main.dart 屏幕。之后,if 查询将我直接发送到 signIn.dart 屏幕。正如预期的那样。但是,当我创建一个新的嵌套屏幕并且 streamProvider 更改其值时,“根”屏幕 (home.dart) 不会将我发送回登录屏幕。所以我想它只适用于第一个孩子而不是嵌套的孩子。

是否可以在根屏幕中只使用一个查询来检查 streamProvider,还是我必须在每个屏幕中都放置一个查询来检查值?

class SignInCheck extends ConsumerWidget 
  @override
  Widget build(BuildContext context, ScopedReader scopedReader) 
    final _authState = scopedReader(firebaseAuthStateProvider); //
    return _authState.when(data: (value) 
      if (value != null) 
        return HomeScreen();
       else 
        return SignIn();
      
      //...

【问题讨论】:

【参考方案1】:

只要***的小部件是监听身份验证状态变化的小部件,所有的孩子都会受到屏幕变化的影响。下面的代码是我不久前在 GitHub 上找到的,并且一直是我所有 Flutter 项目中的 goto。

AuthHome() 是我的***小部件,它是我的应用程序其余部分的父级

auth_home.dart:

class AuthHome extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return AuthWidget(
          signedInBuilder: (context) => NavBase(),
          signedOutBuilder: (context) => Login());
  

auth_widget.dart:

class AuthWidget extends ConsumerWidget 
  AuthWidget(
      required this.signedInBuilder,
      required this.signedOutBuilder);
  final WidgetBuilder signedInBuilder;
  final WidgetBuilder signedOutBuilder;
  

  @override
  Widget build(BuildContext context, watch) 
    final authStateChanges = watch(authStateChangesProvider);
    return authStateChanges.when(
      data: (user) => _data(context, user),
      loading: () => const Scaffold(
        body: Center(
          child: CircularProgressIndicator(),
        ),
      ),
      error: (err, __) 
        print(err);
        return Scaffold(
          body: EmptyContent(
            title: 'Something went wrong',
            message: 'Can\'t load data right now.',
          ),
        );
      ,
    );
  

  Widget _data(BuildContext context, User? user) 
    if (user != null) 
      return signedInBuilder(context);
    
    return signedOutBuilder(context);
  

NavBase() 是应用的其余已验证部分所在的位置

【讨论】:

谢谢,我试过你的代码,效果很好。然而,最初的问题仍然存在。我发现,它只发生在我使用路由并通过 .pushNamed("routeName") 切换页面时。路由可能是问题吗? 没有完整地看到您的实现,我无法进一步阐明可能导致问题的原因。如果代码在 GitHub 上,我可以查看。根据您所说的,如果您推送的路由不是小部件监控身份验证的后代,那么问题将持续存在。

以上是关于如何根据riverpods streamProvider 更新嵌套屏幕?的主要内容,如果未能解决你的问题,请参考以下文章

重走Flutter状态管理之路—Riverpod最终篇

Riverpod - 如何在消费者中包装 PreferredSizeWidget

Riverpod 条件提供程序状态更新

RiverPod - 如何在不在小部件中的 AsyncValue 上等待使用 FutureProvider

如何在 Riverpod 中显示来自 StateNotifier 的小吃店?

Flutter Riverpod:如何实现 FutureProvider?