
Managing state is one of the hottest and somewhat controversial topics in the frontend development world. A lot of effort has been made by several teams across the world to address state management with a clean and simple approach, creating libraries such as Redux, NgRx, RxJS, MobX and many others.
Anything that can be derived from the application state, should be derived. Automatically. (Micheal Weststrate)
At Codemotion Milan 2018, Max Gallo from DAZN gave a nice overview of MobX, highlighting some of its main features.
MobX is a simple and scalable state management library, based on the functional reactive programming paradigm. In a nutshell, it allows us to easily separate views and business logics.
Core concepts
Compared to other state management libraries, MobX is easier to use since it is designed around three core concepts only: observables, computed values and reactions.
An observable is a data structure to monitor, looking for changes. MobX keeps track of any changes of an observable object. Whenever the value of an observable changes, MobX knows it. Any data structure can be marked as observable like objects, arrays, class instances and so on. Making an object observable is as easy as adding one decorator, the @observable decorator, to be precise.
Computed values, as the name implies, are values derived from observables. Every time the observables are modified, the computed values are updated automatically by MobX. Again, a computed value is defined by decorating a variable with the decorator @computed.
The last core concept of MobX is reactions. They are similar to computed values since they are triggered when an observable changes. But instead of computing a value, they execute code. Simply put, reactions tell MobX what to do when an observable changes.
A custom reaction can be created using the autorun function. MobX will execute the function passed to autorun every time one of the observables or computed values referenced in its body changes.
Integration with React
MobX can be easily integrated with React. Thanks to the @observable decorator, it is possible to make a React component be observed. Moreover, the react component can be refreshed (triggering the render() function) automatically whenever the state changes.
MobX State Tree
Unlike other frameworks, MobX is not opinionated about how user events should be handled. Although flexibility is a must for a library such as MobX, sometimes having a predefined structure to follow rather than starting from scratch may help. This is why MobX State Tree (MST) was created. MST is a state container built on top of MobX that allows us to maintain a strongly typed application state: the tree store. The tree store is a set of mutable but strongly typed objects. In MST jargon, the shape of the tree defines its type information while the state represents the data it stores. At any time, snapshots of the tree can be generated. Snapshots are immutable versions of the store, which can be converted to a live tree when needed.
A typical MST store is built providing three key definitions: the model, which describes the structure of the mutable and observable state, the views which contain the output computed values and the actions, which are the interfaces to update the model from outside.
Views can return filtered values by simply using the filter method. Since the values stored in the tree are actually MobX observables, filtered values (which are, in essence, computed values) are updated automatically. Moreover, models in MobX State Tree are composable. Each model can capture only a small piece of the application state, allowing the developer to combine them only when needed. Types can be composed directly or by using the method compose().
MST Dependency Injection
When creating a new store it is possible to provide external data to the create method. External data is used to enrich the store with a proper environment. Anything can be provided, including variables, arrays, functions, utilities etc. Objects passed as environment data are accessible to any descendant in the tree structure by using the function getEnv(self). This mechanism is very useful to inject dependencies to the tree such as loggers, transport functions, test-specific data, etc.
Trees and Forests
MobX State Tree supports more than one tree store per application. Developers can define multiple stores, one per each application domain. While this approach is easier to model when reasoning by domain it less convenient when in need to perform actions on multiple domains at the same time or provide a single environment to all the stores. The alternative pattern is the single root store. Instead of building a forest of tree stores, there is a single hierarchy of stores, all leaves of the same root store. This allows easier global actions and global dependency injection, but can lead to tightly coupled stores, where interactions between stores is possible only by traversing the whole tree structure.
Conclusions
MobX is a great tool to learn reactive programming, as it is easier to use compared to other reactive frameworks. MobX State Tree adds a well-defined structure to model the application on top of MobX, combining the best features of both immutability and mutability.