How to use data from Provider during initState in Flutter application
Asked Answered
B

7

35

I am refactoring my Flutter application code by adding Provider as a state management.

Desired behavior: When Home screen opens, app should check if users email verified, if it's not then should show dialog popup.

Problem: It worked fine when I was passing data for EmailVerified through the constructor, but if I want to use Provider, I can't get this data at initState() lifecycle.

Can you please recommend me correct approach for such use case?

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
  }
}

Bra answered 21/2, 2020 at 17:27 Comment(0)
D
90

You need to use the context to call Provider.of() so you can add addPostFrameCallback() which is called after the first build, there you can use the context

@override
void initState() {
    super.initState();

    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      auth = Provider.of<Auth>(context, listen: false);
    });
}
Dickman answered 21/2, 2020 at 17:44 Comment(6)
Thanks a lot @Dickman . Also if someone else facing this issue, I recommend following article, it explains why showDialog doesn't work as you might expect and what is addPostFrameCallback () needed for - didierboelens.com/faq/week2Bra
@ Sebastian This worked in Android, and not in iOS. In iOS throws error Unhandled Exception: 'package:provider/src/provider.dart': Failed assertion: line 240 pos 12: 'context != null': is not true. Thanks.Eipper
Does this really work or am I missing something? My user is not initialized during build time and dart throws an error. I am using Provider.of<FirebaseAuth>(context, listen:false).currentUser in the addPostFrameCallback()Selfabsorption
Thanks man. Struggling this on several hours.Gresham
Tried it but still gets the error message: The following ProviderNotFoundException was thrown during a scheduler callback: Error: Could not find the correct Provider...Leucomaine
... is it because my NotifierProvider is in the same widget instead of in the parent?Leucomaine
H
14

From Provider v4.1.0, you can also use read() method. It reduces the boilerplate code.

@override
void initState() {
  super.initState();

  WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
    auth = context.read<Auth>();
  });
}
Hypermetropia answered 13/5, 2020 at 2:23 Comment(0)
P
6

You can make your initState as follows:

@override
void initState() {
    super.initState();
    final myModel = Provider.of<YourProivder>(context, listen: false);
}
Pelota answered 15/1, 2022 at 9:54 Comment(0)
C
2
  @override
  void initState() {
    super.initState();

  Future.microtask(() {
      final MapsProvider mapsProvider = context.read<MapsProvider>();
    });
  }
Cavy answered 29/3, 2024 at 12:14 Comment(2)
general solution asynchronous operationsCavy
Although this code might answer the question, I recommend that you also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes.Analeptic
H
0

You can also pass context to HomeScreen widget, which will let you access 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();
    }
  }

...

}
Harbird answered 29/4, 2021 at 20:7 Comment(0)
F
-1

For this, we need to bindwidget. so provider give us this feature too

 WidgetsBinding.instance.addPostFrameCallback((_) {
      auth = Provider.of<Auth>(context, listen: false);
     _isEmailVerified = auth.isEmailVerified()

    });
Frogmouth answered 20/9, 2022 at 14:4 Comment(0)
U
-6

In version 3.0.0+1,you can also do

you can do it with

var CallNotifier auth;


@override
void initState(){
 super.initState();
 auth = Provider.of<CallNotifier>(context, listen = false);
}
Unilateral answered 20/5, 2020 at 7:7 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.