MobX vs. Redux

When working with popular frameworks like React or Vue, we must organize convenient storage and manage the application state. For example, React allows one to manage the state of components out of the box using this.setState and this.state. Yet, with application growth comes the need for communication between components that often results in insufficient functionality. Luckily, in the front-end world, there are many ready-made libraries to help simplify this task. This article discusses two of the most popular solutions at the
moment – Redux and MobX.

About Redux and MobX

Currently, the most popular library for storing application state is Redux, invented in 2015 by Dan Abramov and Andrew Clark. It is based on Flux architecture and functional programming. Redux users get support from a strong community and rich codebase, so getting any question regarding the library answered is no longer an issue.

The most widespread alternative is MobX, invented by Michel Weststrate in 2015. It is implemented in functional reactive programming (FRP) principles and allows wrapping states in ‘observable’ objects. This makes it easy to react to any app state changes.

Data Flow and Key Differences

Redux:

data flow Redux

  • Has only one store as a single source of truth. The state is stored in a regular JavaScript object. It would be best to keep the state normalized and flat.
  • The state is immutable. Any updates to the state always return a new copy of the state.
  • All state updates are done by dispatching a specific action.
  • Reducers respond to actions and return a new copy of the state if it has been updated.

MobX:

data flow MobX

  • Can have multiple observable stores. The state structure is denormalized and often deeply nested.
  • State is mutable. It can be changed directly, but it is recommended to do this using action functions.
  • As the documentation says: “MobX makes state management simple again by addressing the root issue: it makes it impossible to produce an inconsistent state.”
  • All derivations are updated automatically and atomically when the state changes.

Redux Store

As stated earlier, Redux stores state data in a single global store, which is the only source of truth. Reducers that take an action object and return an updated copy of the state are used to manage it. The action object is a simple javascript object containing the action type field and payload fields. Reducers allow you to split a state object into separate logical units, such as artistReducer, articlesReducer, profileReducer, which are later combined into one state object using combineReducers. The store has dispatch and subscribe methods to manage state and respond to changes. If, after calling dispatch, the state gets updated, all subscribers are notified. However, it will take a lot of boilerplate code to describe the store, which is a major drawback for small projects. An example of a store on Redux:

MobX Store

An application that uses MobX, tends to have multiple stores that divide the state into logical chunks, such as a domain model or UI state. This allows you to conveniently organize your state structure and reuse individual stores in other applications. MobX has a fairly high level of abstraction, which significantly reduces boilerplate code compared to Redux. This allows to quickly create stores using @observable and @computed annotations or the makeObservable and makeAutoObservable functions. Any changes to the state can be made either directly, such as artistStore.artists.push(artist), or, as recommended, more explicitly using @action as shown in the example below. The easiest way to react to changes in the store is to create a reaction by passing a callback to the autorun function. The reaction will be called when it is first created and whenever observable, and computed values change in the store. The main disadvantage of this approach is that when applications begin to grow into more complex ones, it leads to unobvious and difficult to debug relationships between stores. The following example describes a MobX store similar to the Redux store presented above:

Popularity & Compatibility

Judging by powerful community support, Redux is undoubtedly more popular than MobX. In this library, any developer can find solutions to the Redux-related problems and use a convenient tool for debugging the state of Redux DevTools. This simplifies the process of mastering the library. However, the need to write a large amount of boilerplate code and many utility libraries and solutions such as redux-saga, redux-thunk, reselect, normalizr, middlewares, etc., is the major cause of headaches people get on the path of mastering it. In the meantime, MobX offers high abstraction in annotations, allowing a rapid shift from learning to working with the library.

MobX and Redux are independent libraries that are compatible with almost all UI frameworks. For popular solutions like React, ready-made packages make it easier to connect and manage states, such as mobx-react or react-redux.

Debugging

Debugging state in Redux is incredibly flexible and transparent thanks to its low level of abstraction, the Flux paradigm, and the handy Redux DevTools. Redux DevTools provides the broadest functionality for debugging state, including time-travel for state changes, import/export of state as a regular .json file, autotest generation, displaying state as a tree, graphs, just to name a few. MobX also has a state debugging utility – MobX DevTools, but its functionality is way more limited compared to the utility for Redux. It allows users to view the state tree of the repository and catch changes in state and the redraw of components. In addition, MobX comes with a number of utilities such as trace and spy that make it easier to debug state.

Final Words

This article considers two libraries aimed at solving one problem but using different methods. We have outlined the pros and cons of each library – the choice is yours. Go for Redux if working with a flexible, scalable, debuggable, and more popular state store is your priority, and a lot of boilerplate code is not a problem. However, for quick implementation storage in a small MVP or PoC project, one should adopt MobX. Below is a short list of pros and cons that should help you decide on the right tool for your task.

MobX Redux
Pros
  • Easy to learn
  • A small amount of boilerplate code
  • Full TypeScript support
  • Great community support
  • Easy debugging and testing
  • Flexibility and extensibility thanks to pure reducer functions and middlewares
Cons
  • Challenging debugging
  • High level of freedom in terms of data storing, structuring, and processing
  • Complicated scaling that comes with a project’s growth
  • Lots of boilerplate code
  • Lack of side effects out of the box
  • The need to learn many additional libraries
MobX
Pros
  • Easy to learn
  • A small amount of boilerplate code
  • Full TypeScript support
Cons
  • Challenging debugging
  • High level of freedom in terms of data storing, structuring, and processing
  • Complicated scaling that comes with a project’s growth
Redux
Pros
  • Great community support
  • Easy debugging and testing
  • Flexibility and extensibility thanks to pure reducer functions and middlewares
Cons
  • Lots of boilerplate code
  • Lack of side effects out of the box
  • The need to learn many additional libraries