Search code examples
flutterreduxflutter-redux

Flutter redux Navigator.pop() in StoreConnector after user login


How I can do Navigator.of(context).pop((route) => false); on my Login screen?

class _LoginState extends State<Login> with SingleTickerProviderStateMixin {
  String email = '';
  String password = '';
  final Store<AppState> store;
  final _formKey = GlobalKey<FormState>();

  _LoginState(this.store);

  
  @override
  Widget build(BuildContext context) {
    return new StoreConnector<AppState, LoginViewModel>(
      converter: ((Store<AppState> store) => LoginViewModel.create(store)),
      builder: (BuildContext context, LoginViewModel viewModel)  {
        if(viewModel.user.email != '') {
           Navigator.of(context).pop((route) => false);
           return null;
        }
        return (
          viewModel.isLoading ? 
            Center(...)
            :
            Scaffold(...)

The above code works but throws the following errors:

Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4167:11)
I/flutter (13435): #1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4182:6)
I/flutter (13435): #2      State.setState (package:flutter/src/widgets/framework.dart:1253:14)
...

Solution

  • Ideally, you should not call Navigator inside the widget tree hence you are getting an error.

    To do so StoreConnector has onWillChange method. It is a function that will be run on State change, before the Widget is built. (Similar to componentWillUpdate in react class components)

    class _LoginState extends State<Login> with SingleTickerProviderStateMixin {
      String email = '';
      String password = '';
      final Store<AppState> store;
      final _formKey = GlobalKey<FormState>();
    
      _LoginState(this.store);
    
    
      @override
      Widget build(BuildContext context) {
        return new StoreConnector<AppState, LoginViewModel>(
          converter: ((Store<AppState> store) => LoginViewModel.create(store)),
          onWillChange: (LoginViewModel prev, LoginViewModel viewModel) {
            if(viewModel.user.email != '') {
               Navigator.of(context).pop((route) => false);
               return null;
            }
          },
          builder: (BuildContext context, LoginViewModel viewModel)  {
            return (
              viewModel.isLoading ? 
                Center(...)
                :
                Scaffold(...)
    

    You can explore other methods exposed by StoreConnector in the source code. (Github Link)