Search code examples
flutterdartmobxstate-management

Forcing the MobX state to be changed through declared actions only in the Flutter framework


I'm experimenting with MobX state management solution in Flutter. I really like its conciseness and its simplicity but I'm a bit concerned in the drawbacks its way of mutating the state can introduce. Theoretically , we can force the state to be mutated only using actions and this is great because we can have a history of the changes using the spy feature the package provides. However, actions are automatically created by the framework if we do not use a specific one. For example, in the code below, I created a counter store class and I used it in the main function to assign a new value for the counter without using a predeclared action. The stric-mode has been previously set to "always".


abstract class _Counter with Store {
  @observable
  int value = 0;

  @action
  void increment() {
    value++;
  }
}

final counter = Counter(); // Instantiate the store
void main() {
  mainContext.config = mainContext.config
      .clone(isSpyEnabled: true, writePolicy: ReactiveWritePolicy.always);
  mainContext.spy((event) {
    print("event name : " + event.name);
    print("event type : " + event.type);
  });
  Counter counter = Counter();
  counter.value = 10;
}

I was expecting an error to raise saying that it is not possible to change the state outside of action but this does not happen because an ad hoc action is created , called value_set, automatically. I'm wondering ,then, which is the point of forcing to use actions if it is possible to avoid using them. I mean, if we directly change the state, an action is created automatically and seen by the spy functionality making all the process more robust and predictable but, what if I want the state to be changed only by actions I previously implemented? Is there a way of doing so? For example, in the counter code I just provided , is there a way of making the counter incrementalbe only by 1? Because, in the way Mobx works, I could write everywhere in the code something like

counter.value = 10

and this will work just fine without any problems. Forcing people to use preset actions could increase the predicatability a lot and facilitate the teamwork too I think. I tried to make the value variable private but it still remains accessible from the outside , also if annotated with @readonly.


Solution

  • At the end, I found out that the behaviour I was looking for was obtainable with the @readonly annotation. Marking a variable with @readonly annotation avoids automatically creating its setter and getter methods. Moreover it requires the annotated variable to be private, denying the variable to be set directly.

    Note: By the way, the way the Dart language is implemented, it is necessary to locate the Counter in a separate file to provide the desired behaviour, otherwise its private fields would be accessible anyway.