Redux vs MobX: What you need to know
Before getting into a comparison between two of the most popular state management libraries used today, let’s first understand the need for a state management library. What does Redux or MobX bring to the table that simply cannot be accomplished with ‘this.setState’ and ‘this.state’?
When an application is built using a component-based library, such as ReactJs, each component maintains its own local state and generally the root component maintains the state of the application. Multiple components interact with the state data at any given time and change it before sending it back to the server. Also, components may maintain their state across component life cycle methods. As application complexity grows, component state becomes unpredictable and debugging such application becomes a lengthy process.
To avoid such scenarios, the state management systems (Redux/MobX in case of ReactJS) move state out of components as a stand-alone testable unit and provide mechanisms to synchronise application state with react components. The reasoning of your application code becomes easier, when data originates from a single source of truth.
You can select either of the libraries, based on the application complexity and requirements.
Comparison between Redux and MobX
You can compare the two libraries based on:
- Data flow logic
- Describing UI as a function of state
- Plain data structure versus observable data structure
- Mutable and immutable stores
- Plain data structure v/s observable data structure
Data flow logic
According to Redux documentation:
“Redux architecture revolves around a strict unidirectional data flow”.
To update the state, an event or action has to be dispatched. Based on the action type, a pure function, known as the ‘reducer’, updates the application state.
MobX also supports a unidirectional data flow, where actions change the state (without the need for a reducer), which in turn updates all the affected views. In MobX, State data is observable; when data changes in state, it automatically triggers a re-render of views (components).
To achieve the same outcome in corresponding redux code, new actions and reducers have to be maintained that bring a lot of boilerplate code for large applications. MobX, on the other hand, resolves the issue of large boilerplate code by abstraction. MobX automatically adds listeners to detect changes in observable data.
Listeners recursively call observable(newValue) for any newly assigned value. For any change in observable data, mobx.autorun() gets called. To re-render the component (reactive) due to change of state value, you just have to write @observable on top of react component. @observable enables the mobx.autorun() method implicitly to encapsulate render() method.
Describing UI as a function of state
Single store vs multi stores
Redux maintains a single store for the entire application. By doing so, debugging becomes easier and time travel is possible, as the Redux state is immutable and for each new state, an ancestor state is cloned.
MobX maintains at least two stores. One for the UI state and one or more for the domain state. The advantages of separating these two is that you can reuse and test the domain state universally (for example, you can use store inside another store) and reuse it in other applications.
Domain state is the state of the server side of the application. For example:
Online food order application– you can expect to find the following state in the application:
Authentication, validation, and error states, as well as state specific to the e-commerce industry. Domain state comes from the server, as this state needs to persist across user sessions.
All relevant information pertaining to overall UI is maintained in the UI State. For example, Hiding/showing components, reacting to user interaction, collecting user inputs, and so on.
So, single or multi store selection is completely dependent on requirements. For efficient debugging and consistent behaviour of data, you can opt for single store. To reuse the store in other applications then opt for multi store.
Plain data structure Vs. observable data structure
Observable automatically track changes through implicit subscriptions. Any observable property that is DE-referenced in a track function will be recorded. If any reference is changed, MobX will react. The track function is a computed function that takes observable data and returns new data.
So, the observability mechanism promotes less code and high abstraction and automatically track updates that makes React component reactive. Redux track updates manually and React component react passively on state changes, until listeners are manually added.
Mutable and immutable store
Redux state is read-only, reducers take the previous state and action as parameters and return a new state.
You can read and write the write MobX store.
Data integrity and consistency are maintained in Redux, irrespective of the application complexity. Consistency and data integrity might be compromised in the MobX state, if the application is highly complex.
Normalized and denormalized data
it is recommended that data in the Redux state be normalized. When immutable data is updated, all ancestors in the tree must be copied and updated as well. If data is not normalized, components that depend on a particular state might be updated, even if no actual update is triggered.
MobX keeps the state as denormalized.
MobX keeps denormalized data, as it uses the computed concept, which keeps track of state data and updates components only when relevant data is updated. For an object oriented programmer, working with MobX will be quite easier than with Redux.
- Selection of any state management library should be based on complexity of an application. MobX state can be updated without triggering an action. Keeping track of unnecessary state updates in a complex application is difficult.
- If the application is small, then MobX is a better option, as it highly abstracts the mechanism of updating a component based on state changes.
- Learning curve in Redux is steep and for big applications there will be so much boilerplate code.
- If you want to debug your application efficiently and want to have great control of flow of data, Redux is a good option.
At the end of the day, it depends on what library you wish to use and are comfortable with.