Statemanagement Flutter: Consumer not notified

22 views Asked by At

neither ChatGPT nor looking at other questions has been helpful so far, so I hope you can help me with this issue. I already have a hunch what the problem might be, but am unsure as to how I could fix it.

So I am unexperienced with state management, but have watched a lot of videos and have read up on it, so the general idea is clear and much of it is already working.

GIF showing the current state of the app

@override
Widget build(BuildContext context) {
  return ChangeNotifierProvider(create:(context) => AuthProvider(),
    child: MaterialApp(
      initialRoute: '/map_selection',
      onGenerateRoute:(settings) => RouteGenerator.generateRoute(settings),
    ),
  );
}

I have wrapped my entire app with an AuthProvider which notifies about login logout etc. As you can see in the beginning of the video, this is working in the "normal" case. That is, when I am logged in I can logout using the upper right button and the state changes to displaying the login button instead.

However, when I press the login button to get to the authentication screen and login, the login button is still there instead of showing the logout one. If I restart the app I am logged in and everythin is as in the GIF. I am guessing that this has to do with my use of the navigator here or the asynchronity of the code I might not be getting 100%. My idea is that the app should be usable without being logged in but that certain functionalities such as saving items etc. are only added once logged in. Thus, I am pushing the login screen on top of the homescreen when clickin the login button and then popping it again once logged in like so:

if (_formKey.currentState!.validate()) {
  dynamic result = await _authProvider.signInWithEmail(emailController.text, passwordController.text);
  if (result is String) {
    setState(() => error = result,);
  } else {
    if (context.mounted) {
      Navigator.pop(context);
    }
  }
}

When I debug step by step I can see that instead of notifying the listeners, the app jumps back to the code of the signin screen popping the Navigator and returning to the unchanged homescreen (which was supposed to be rerendered based on it being a consumer of the AuthProvider).

Future signInWithEmail(String email, String password) async {
  try {

    UserCredential result = await _auth.signInWithEmailAndPassword(
      email: email.trim(), 
      password: password.trim()
    );
    User? user = result.user;
    notifyListeners();
    return user;

  } catch (e) {

    List<String> error = e.toString().split(']');
    return error[1].trim();

  }
}

Do you have an idea what the issue might be and how I could fix it?

Thank you in advance!

All the best

1

There are 1 answers

1
Vandan Patel On

When you're sign method is success you are using pop method, so that it just remove the sign in screen, it will not update your homescreen.

You have to use the pushReplacement method so that it remove the singin screen and show the Homescreen.

if (_formKey.currentState!.validate()) {
  dynamic result = await _authProvider.signInWithEmail(emailController.text, passwordController.text);
  if (result is String) {
    setState(() => error = result,);
  } else {
    if (context.mounted) {
      Navigator.pushReplacement(
                      context,
                      MaterialPageRoute(
                        builder: (context) => const HomeScreen(),
                      ),
                    );
    }
  }
}

Concept - Screen only update when you call, while in pop it just remove the top of the screen and show the below one. It will on call that below one screen that's it not updating it self.