Now that we understand the roles of UI, state, and actions, we can extend this to build a mental model of how a UI needs to operate. Reflecting back on the triad of
UI, we can make some interesting observations that are not clearly answered. Let's think about how we would handle operations such as the following:
- Downloading data from a server
- Persisting data back on the server
- Running a timer and doing something periodically
- Executing some validation logic when some state changes
These are things that don't fit nicely in our data flow triad. Clearly, we are missing something here, right? You might argue that you could put these operations inside the UI itself and fire actions at certain times. However, that would tack on additional responsibilities to the UI, complicating its operation and also making it difficult to test. From a more academic perspective, it would also violate theSingle Responsibility Principle(SRP). SRP states that a class or a module should have only one reason to change. If we start handling additional operations in the UI, it would have more than one reason to change.
So, it seems like we have some opposing forces in action here. We want to retain the purity of the data flow triad, handle ancillary operations such as the ones mentioned in the preceding list, and not add extra responsibilities to the UI. To balance all of these forces, we need to think about the ancillary operations as something external to the data flow triad. We call these side effects.
Side effects are a result of some state-change and are invoked by responding to the notifications coming from the state. Just like the UI, there is a handler, which we can call the side effect handler, that observes (subscribes to) the state change notifications. When a matching state change happens, the corresponding side effect is invoked:
There can be many side effect handlers in the system, and each of them is an observer of the state. When a part of the state they are observing changes, they will invoke the corresponding side effects. Now, these side effects can also cause a change in state by firing additional actions.
As an example, you could fire an action from the UI to download some data. This results in a state change to some flag, which results in notifications being fired to all the observers. A side effect handler that is observing the flag will see the change and trigger a network call to download data. When the download completes, it will fire an action to update the state with the new data.
The fact that side effects can also fire actions to update the state is an important detail that helps in completing the loop around managing state. So, it's not just the UI that can cause state changes, but also external operations (via side effects) that can affect a state change. This is the mental model of side effects, which can be used to develop your UI and manage the state that it renders. The model is quite powerful and scales very well over time. Later in this chapter and also throughout this book, you will see how MobX makes this side effect model a reality and fun to use.
With these concepts in mind, we are now ready to enter the world of MobX.