Flutter what is the best approach to use navigator and ChangeNotifierProvider together

Issue

I’m new to flutter, this question may be a very basic one.
I have a firebase phone auth login page to implement this,
if the user is logged in, then navigate to home page
else if the user is a new user, then navigate to the sign-up page

The problem is, whenever the values are changed at the provider, the consumer will get notified and rebuild the build method. I won’t be able to listen to them within the build method and return a Navigator.of(context).pushNamed(). Any idea what is the right way to use ChangeNotifierProvider along with listeners and corresponding page navigation?

I have Login class and provider class as below,

class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
        @override
          Widget build(BuildContext context) {
            return ChangeNotifierProvider(
              create: (_) => LoginProvider(),
              child: Consumer<LoginProvider>(builder: (context, loginState, child) {
                return Scaffold(
                  ...
                  body: RaisedButton(
                  onPressed: **loginState.doLogin(_textController.text, context);**
                   ...
                )
              }),
           );
         }
   }

class LoginProvider with ChangeNotifier {
     bool _navigateToSignup = false;
     bool get navigateToSignup => _navigateToSignup;

    Future doLogin(String mobile, BuildContext context) async {
        FirebaseAuth _auth = FirebaseAuth.instance;
        _auth.verifyPhoneNumber(
          ...
          verificationCompleted: (AuthCredential credential) async {
          UserCredential result = await _auth.signInWithCredential(credential);
          User user = result.user;
          // if user is new user navigate to signup
          // do not want to use Navigator.of(context).pushNamed('/signupPage'); here, instead would like to notify listeners at login page view and then use navigator.
          if (user.metadata.creationTime == user.metadata.lastSignInTime) {
            _navigateToSignup = true;
          } else {
            if (result.user != null) {
              _navigateToHome = true;
              //Navigator.of(context).pushNamedAndRemoveUntil('/homePage', ModalRoute.withName('/'));
            } 
          }
          notifyListeners();
        },
          ...
         );
    }
}

Thanks in advance.

Solution

There are several approaches, you choose the one that suits you best.

  1. Pass the context to the ChangeNotifier as you are already doing. I don’t like this as well, but some people do it.

  2. Pass a callback to your ChangeNotifier that will get called when you need to navigate. This callback will be executed by your UI code.

  3. Same as 2, but instead of a callback export a Stream and emit an event indicating you need to Navigate. Then you just listen to that Stream on your UI and navigate from there.

  4. Use a GlobalKey for your Navigator and pass it to your MaterialApp, than you can use this key everywhere. More details here.

Answered By – Michel Feinstein

Answer Checked By – Dawn Plyler (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *