【问题标题】:How to use data from Provider during initState in Flutter application如何在 Flutter 应用程序的 initState 期间使用来自 Provider 的数据
【发布时间】:2020-06-06 04:13:13
【问题描述】:

我正在通过添加 Provider 作为状态管理来重构我的 Flutter 应用程序代码。

期望行为:当主屏幕打开时,应用程序应检查用户的电子邮件是否已验证,如果未验证,则应显示对话框弹出窗口。

问题:当我通过构造函数为 EmailVerified 传递数据时它工作正常,但如果我想使用 Provider,我无法在 initState() 生命周期获取此数据。

您能否推荐我针对此类用例的正确方法?

import 'package:myapp/services/authentication.dart';
import 'package:myapp/screens/settings_screen.dart';
import 'package:flutter/material.dart';
import 'package:myapp/services/authentication.dart';
import 'package:provider/provider.dart';

class HomeScreen extends StatefulWidget {

  @override
  State<StatefulWidget> createState() => new _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final GlobalKey<FormState> formKey = GlobalKey<FormState>();
  bool _isEmailVerified = false;

  @override
  void initState() {
    super.initState();
    _checkEmailVerification(); // <=== Method which should show Dialog box if email is not verified which is coming from "Auth" Provider
  }

  @override
  Widget build(BuildContext context) {
    final auth = Provider.of<Auth>(context, listen: false); // <==== Service from Provider, which contains data for _isEmailVerified
    auth.isEmailVerified().then((value) => _isEmailVerified = value);

    return new Scaffold(
      appBar: new AppBar(
        title: new Text('My App'),
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            Text(
              'Welcome to my app',
            ),
          ],
        ),
      ),
    );
  }

  void _checkEmailVerification() async {
    _isEmailVerified = auth.isEmailVerified(); // <=== How can I use "auth" from Provider to get isEmailVerified data ????
    if (!_isEmailVerified) {
      _showVerifyEmailDialog();
    }
  }

  void _showVerifyEmailDialog() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        // return object of type Dialog
        return AlertDialog(
          title: new Text("Verify your account"),
          content: new Text("Please verify account in the link sent to email"),
          actions: <Widget>[
            new FlatButton(
              child: new Text("Resend link"),
              onPressed: () {
                Navigator.of(context).pop();
                _resentVerifyEmail();
              },
            ),
            new FlatButton(
              child: new Text("Dismiss"),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }

  void _resentVerifyEmail() {
    // Logic to send email
  }
}

【问题讨论】:

    标签: flutter flutter-layout state-management flutter-provider flutter-state


    【解决方案1】:

    你需要使用上下文来调用Provider.of(),所以你可以添加addPostFrameCallback()在第一次构建之后调用,你可以使用上下文

    @override
    void initState() {
        super.initState();
    
        WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
          auth = Provider.of<Auth>(context, listen: false);
        });
    }
    

    【讨论】:

    • 非常感谢@Sebastian。另外,如果其他人遇到此问题,我建议您阅读以下文章,它解释了为什么 showDialog 不能像您预期的那样工作以及 addPostFrameCallback () 需要什么 - didierboelens.com/faq/week2
    • @Sebastian 这在 Android 中有效,在 iOS 中无效。在 iOS 中抛出错误 Unhandled Exception: 'package:provider/src/provider.dart': Failed assertion: line 240 pos 12: 'context != null': is not true。谢谢。
    • 这真的有效还是我错过了什么?我的用户在构建期间未初始化,dart 抛出错误。我在addPostFrameCallback()中使用Provider.of&lt;FirebaseAuth&gt;(context, listen:false).currentUser
    • 谢谢伙计。挣扎了几个小时。
    【解决方案2】:

    Provider v4.1.0,你也可以使用read()方法。它减少了样板代码。

    @override
    void initState() {
      super.initState();
    
      WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
        auth = context.read<Auth>();
      });
    }
    

    【讨论】:

      【解决方案3】:

      您也可以将context 传递给HomeScreen 小部件,这样您就可以访问Provider

      class HomeScreen extends StatefulWidget {
        final BuildContext context;
        HomeScreen(this.context);
      
        @override
        State<StatefulWidget> createState() => new _HomeScreenState();
      }
      
      class _HomeScreenState extends State<HomeScreen> {
        bool _isEmailVerified = false;
      
        void _checkEmailVerification() async {
          _isEmailVerified = widget.context.read<Auth>().isEmailVerified();
          if (!_isEmailVerified) {
            _showVerifyEmailDialog();
          }
        }
      
      ...
      
      }
      

      【讨论】:

        【解决方案4】:

        您可以按如下方式设置您的 initState:

        ''''
         @override
            void initState() {
               super.initState();
               final myModel = Provider.of<YourProivder>(context, listen: false);
          }
        ''''
        

        【讨论】:

          【解决方案5】:

          在3.0.0+1版本中,你也可以这样做

          你可以这样做

          var CallNotifier auth;
          
          
          @override
          void initState(){
           super.initState();
           auth = Provider.of<CallNotifier>(context, listen = false);
          }
          

          【讨论】:

            猜你喜欢
            • 2021-04-12
            • 2021-05-22
            • 2021-01-21
            • 2019-04-29
            • 1970-01-01
            • 2020-02-29
            • 2021-07-14
            • 2019-12-24
            • 1970-01-01
            相关资源
            最近更新 更多