Skip to content

ViewModel structure

Valdio Veliu edited this page Mar 31, 2020 · 1 revision

The ViewModels purpose is to be "the man in the middle" between the View layer and the data layer. So simply said, it provides to the VIEW access to the necessary data and provides a way for the view to request changes to these data.

What I usually prefer, but is not mandatory, is to create a ViewModel for every feature off the app but not necessarily. My rule is "One ViewModel for One responsibility/purpose" so this usually ends up in feature-based ViewModels.

The following example of the settings screen ViewModel present in the demo. It's a straightforward implementation containing. At the top of the file, there are the variables/data declaration that will be required from this ViewModel and a set of function/method declarations to request changes on these data.

Furthermore, this file will contain the actual logic behind each of the methods implemented in the factory constructor. Using the factory keyword when implementing a constructor that doesn’t always create a new instance of this class. What is also known as the "singleton pattern".

class SettingsViewModel {
  final bool darkModeOn;
  final int randomNumber;

  final Function() toggleDarkMode;
  final Function() generateRandomNumber;

  SettingsViewModel({
    @required this.darkModeOn,
    @required this.randomNumber,
    @required this.toggleDarkMode,
    @required this.generateRandomNumber,
  });

  factory SettingsViewModel.create(Store<AppState> store) {
    _onToggleDarkMode() {
      store.dispatch(ToggleDarkModeAction());
    }

    _onGenerateRandomNumber() {
      store.dispatch(GenerateRandomNumberAction());
    }

    return SettingsViewModel(
      darkModeOn: store.state.settingsData?.darkModeEnabled,
      randomNumber: store.state.settingsData?.randomNumber,
      toggleDarkMode: _onToggleDarkMode,
      generateRandomNumber: _onGenerateRandomNumber,
    );
  }
}

Besides the structure of the class, it's worth mentioning that since we are using redux, the data variables declared in this class are mapped to specific parts of the redux store. You can also apply any kind of filtering logic here and expose filtered data for example. This reduces the need for data manipulation at the VIEW layer.

Furthermore, the example illustrates the use of redux actions that are dispatched in the mapped ViewModel functions. This is the usual/default way we manage the redux store. Actions are dispatched (may contain some data attached to the actions) and these actions are intercepted from each corresponding reducers which in return will update the redux store. More about this on the redux config wiki.

So it's obvious that the ViewModel needs a reference to the redux store for both to get data from it and to dispatch actions to modify the store. That's why:

factory SettingsViewModel.create(Store<AppState> store){
  /// ...
}
Clone this wiki locally