Navigate to a new screen and passing the redux store state when using a viewmodel

1,374

For the most common use case of an app wide state you can just use the StoreConnector in any screen where you need the state. You are already using it in your Menu class, but you can use it similarly in your MySettingsScreen build method override.

Additionally your view models are being created using the store, so the idea is that you include all information that is required from the store to build the view when you build the view model. For example:

class MyViewModel {
    String myInfo;
    factory MyViewModel.create(Store<AppState> store) {
        return MyViewModel(myInfo: store.state.myInfoState);
    }
...
}

Then you use that information from your viewmodel:

  @override
  Widget build(BuildContext context) => StoreConnector<AppState, MyViewModel>(
    converter: (Store<AppState> store) => MyViewModel.create(store),
    builder: (BuildContext context, MyViewModel viewModel) {
      return Text(viewModel.myInfo);
  }

You could use the same mechanism to keep a reference to the store in the viewModel:

class MyViewModel {
    Store<AppState> myStore;
    factory MyViewModel.create(Store<AppState> store) {
        return MyViewModel(myStore: store);
    }
...
}

This allows you to use it in your build method directly:

  @override
  Widget build(BuildContext context) => StoreConnector<AppState, MyViewModel>(
    converter: (Store<AppState> store) => MyViewModel.create(store),
    builder: (BuildContext context, MyViewModel viewModel) {
      return Text(viewModel.myStore.state.myInfo);
  }

Note that the first pattern may be preferable if you want to keep a logical separation between the view model and the redux persistence.

Share:
1,374
Giacomo M
Author by

Giacomo M

I am a programmer since about 2000.

Updated on December 03, 2022

Comments

  • Giacomo M
    Giacomo M over 1 year

    I have the need to pass the redux store state from a screen to another inside the build function.
    My problem is that in the build function I have the ViewModel variable, that does not have a reference to the state.

    This is the code of the screen:

    import ...
    
    class Menu extends StatefulWidget {
      @override
      _MenuState createState() => _MenuState();
    }
    
    class _MenuState extends State<Menu> {
    
      @override
      Widget build(BuildContext context) {
        return StoreConnector<AppState, ViewModelLogin>(
          converter: (store) => ViewModelLogin.create(store),
          builder: (context, ViewModelLogin viewModel) {
            Widget _buildPage(isLoggedIn) {
              if (isLoggedIn) {
                return ListView(
                  children: <Widget>[
                    ListTile(
                      title: Text('Settings'),
                      onTap: () {
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                            builder: (context) => MySettingsScreen(), // <-- HERE I NEED TO PASS THE STATE TO MySettingsScreen
                          ),
                        );
                      },
                    ),
                    ListTile(
                        leading: Image.network(
                          viewModel.loginType == 'facebook'
                              ? 'https://img.icons8.com/color/52/000000/facebook.png'
                              : 'https://image.flaticon.com/teams/slug/google.jpg'
                          ,
                          width: 30.0,
                        ),
                        title: Text('Exit'),
                        onTap: () {
                          viewModel.onLogout(viewModel.loginType);
                        }
                    ),
                  ],
                );
              } else {
                return LoginScreen(appBar: false);
              }
            }
    
            return _buildPage(viewModel.isLoggedIn);
          },
        );
      }
    }
    

    The reason I need to pass the state to MySettingsScreen is that in the screen I need a store variable to do a get call to a webservice (outside the build function).

    This is a part of MySettingsScreen where I need the store state:

    import ...
    
    class MySettingsScreen extends StatefulWidget {
      final AppState state;
    
      MySettingsScreen({Key key, @required this.state}) : super(key: key);
    
      @override
      _MySettingsScreenState createState() => _MySettingsScreenState();
    }
    
    class _MySettingsScreenState extends State<MySettingsScreen> {
      @override
      void initState() {
        super.initState();
    
        _load();
      }
    
      void _load() async {
        final url = 'url';
    
        try {
          http.Response res = await http.get(url, headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + // <-- HERE I NEED THE STORE VARIABLE
          });
          final data = json.decode(res.body);
          tmpItems = _parseItems(data["bookings"]);
        } catch(e) {
          print(e);
        }
      }
    
      @override
      Widget build(BuildContext context) {
        ...
      }
    }
    
  • Michael Osofsky
    Michael Osofsky over 4 years
    When the user interacts with the view I'm wondering if the ViewModel responds by dispatching actions to the reducer. What role does the ViewModel play in event handling in an Android app modeled after Redux?
  • EDPChinthana
    EDPChinthana over 3 years
    Is there any way to pass store reference to a function and change the redux store from there? I am a beginner to flutter and redux. Please don't mind if this is a silly question:C