1

I have a simple flow:

  • a UserModel implementing ChangeProvider which wraps the state of the user (if it is logged in and utilities to log him in/out). In particular logout looks like:

    void logout() {
       user = null;
       notifyListeners();
    }
    
  • a UserPage widget with (among others):

    class UserPage extends StatelessWidget {
         @override
         Widget build(BuildContext context) {
             // ... adding only relevant code
    
             // a text with the user first letter of the email
             Text(context.watch<UserModel>().user.email[0])
    
             // a logout button with the following onPressed method
             TextButton( \\ ...
                 onPressed: () { 
                   context.read<UserModel>().logout();  
                   Navigator.pop(context); 
                 }
             )
         }
    }
    

I was expecting that pressing logout and popping the UserPage widget will not let flutter rebuild it. However it is not the case and the notifyListeners() in logout method makes flutter rebuild the widget and trigger a NullPointerException (since the user is null and the email can't be accessed).

I could deal with it (checking if the user object is != null but I would like to understand why this happens).

Is it correct to assume pop destroys the widget? If not, how should I handle this case? When a user is logged out I don't want to have in memory this widget nor deal with its existence. I would expect to create a UserPage when a user logs in and destroy it after its logout

alexlipa
  • 1,131
  • 2
  • 12
  • 27

1 Answers1

1

When you call logout , watch in this line Text(context.watch<UserModel>().user.email[0]) will cause the widget it's in to rebuild.

You need to call logout in the call back of push the one you called to push this page. pop can also send values to inform about the conditions like success or failure.

So it would be something like this:

Navigator.pushNamed(context, some_route).then(value) {
context.read<UserModel>().logout();  
}

value in the call back can be returned from pop like so Navigator.of(context).pop(true);

This will ensure that logout is only called after the widget has been popped.

If you don't like callbacks you can use async await pattern.

moneer alhashim
  • 800
  • 4
  • 11
  • thanks, your answer and then googling found this (https://flutter.dev/docs/cookbook/navigation/returning-data) and it helps! Right now though the screen is popped, then the logout procedure (a network call) starts and then the `UserPage` gets refreshed. Is there a way to make sure the `UserPage` screen is showed after that the logout procedure is done? – alexlipa May 24 '21 at 16:02
  • You got it! Let's say for example you are using one screen for logging in and user page, and these are just one screen and some state determines what UI will show. In such a case you don't need to pop the screen right as your rebuild done by calling `logout` will suffice - you will just need to write the logic to take care of what to show based on the state of the user being logged in or not. If you have separate screens then you can use `popAndReplace`, but definitely don't pop, and push the same screen. – moneer alhashim May 25 '21 at 07:25