Pull to refresh

MobX or Redux: Which is Better For React State Management?

Reading time 5 min
Views 19K


In JavaScript, state management is a hot of discussion these days. When it comes to implementing state management, developers often find it challenging dealing with boilerplate code in Redux. Hence, MobX has proved to be a good alternative to Redux which gives the same functionality with less code to write. However, both state management tools work well with React.

Let's first have a look at the common things between the two:

1) Both support time-travel debugging
2) Both contain open-source libraries
3) Both provide a client-side state management
4) Both provide huge support for React native frameworks

In this blog, we have listed all the pros and cons of both state management solutions. It will help web developers to choose the best one for their next project. Before discussing this, we have compared both Redux and Mobx based on some parameters as given below:

-> Maintenance & Scalable

Due to the presence of pure functions & functional programming paradigm, Redux is more scalable & maintainable. Hence, things cab be easily controlled with Redux.

-> Debug process

Debugging in Redux is a good experience as compared to MobX as it provides awesome developer tools and comes with less abstraction. With the flux paradigm, the Redux becomes more predictable. On the other hand, due to more abstraction and average developer tools, debugging in MobX is a lot harder.

-> Learning curve

To learn MobX is easy as it comes with a steady learning curve. The presence of maximum abstraction makes it easy to learn and JavaScript developers familiar with OOP concepts have a stronghold on MobX. On the other hand, Redux uses a functional programming paradigm which makes it hard to grasp in straightway.

-> Community

Redux has a large community base as compared to MobX. Hence, Redux provides great community support to developers anytime at any place.

-> Impure vs pure

MobX is impure as the states can be overwritten. Here, you can easily update states with the new values. However, Redux is pure as it uses pure functions. Here, the states are read-only and it cannot be directly overwritten. The previous state gets replaced with a new state.

-> Observable vs plain data

MobX uses an observable to store while Redux uses normal Javascript data to store values. In Redux, all updates are tracked manually.

-> Store

A store is something where data is placed. MobX has more than one store where these stores are logically separated. On the other hand, Redux has one large store where all states are stored. The data is usually normalized in Redux and data is kept denormalized in MobX.

Redux vs MobX: The Code Comparison

Props injection

React-redux’s connect() function is used to pass state and actions to props in Redux. It is shown below:

// accessing props

<ContactForm
    contact={this.props.contact}
    loading={this.props.loading}
    onSubmit={this.submit}
  />


// function for injecting state into props

function mapStateToProps(state) {
  return {
    contact: state.contactStore.contact,
    errors: state.contactStore.errors
  }
}


// injecting both state and actions into props

export default connect(mapStateToProps, { newContact,
  saveContact,
  fetchContact,
  updateContact
})(ContactFormPage);


In MobX, inject is used to inject the stores' collection. This will make stores available in props. Here, state and actions are accessed via properties in the store object so no need to pass them separately.

@inject("stores") @observer // injecting store into props
class ContactFormPage extends Component {
…
  // accessing store via props
  const { contactStore:store } = this.props.stores;
  return (
      <ContactForm
        store={store}
        form={this.form}
        contact={store.entity}
      />
  )
…
}


Hence, we used redux-connect-decorators to simplify the Redux code and the MobX version is always easy to read. Hence, no such clear winner.

Bootstrapping

In Redux, first, define store and App is passed via Provider. To handle asynchronous functions, you also need to define redux-thunk and redux-promise-middleware. After this, redux-devtools-extension allow debugging store in time-traveling mode.

import { applyMiddleware, createStore } from "redux";
import thunk from "redux-thunk";
import promise from "redux-promise-middleware";
import { composeWithDevTools } from 'redux-devtools-extension';
import rootReducer from "./reducers";

const middleware = composeWithDevTools(applyMiddleware(promise(), thunk));

export default createStore(rootReducer, middleware);


// src/index.js

ReactDOM.render(
  <BrowserRouter>
    <Provider store={store}>
      <App />
    </Provider>
  </BrowserRouter>,
  document.getElementById('root')
);


In MobX, multiple stores are set up. It does not need external libraries to handle async actions but only a few lines of code. You need the mobx-remotedev for connecting redux-devtools-extension debugging tool.



import remotedev from 'mobx-remotedev';
import Store from './store';

const contactConfig = {
  name:'Contact Store',
  global: true,
  onlyActions:true,
  filters: {
    whitelist: /fetch|update|create|Event|entity|entities|handleErrors/
  }
};

const contactStore = new Store('api/contacts');

const allStores = {
  contactStore: remotedev(contactStore, contactConfig)
};

export default allStores;


// src/index.js

ReactDOM.render(
  <BrowserRouter>
    <Provider stores={allStores}>
      <App />
    </Provider>
  </BrowserRouter>,
  document.getElementById('root')
);


The amount of code used in both is however same. But, MobX contains fewer import statements.

Defining actions & reducers

Actions & reducers are defined in Redux by following code:

// actions

export function fetchContacts(){
  return dispatch => {
    dispatch({
      type: 'FETCH_CONTACTS',
      payload: client.get(url)
    })
  }
}


// reducers

switch (action.type) {
    case 'FETCH_CONTACTS_FULFILLED': {
      return {
        ...state,
        contacts: action.payload.data.data || action.payload.data,
        loading: false,
        errors: {}
      }
    }

    case 'FETCH_CONTACTS_PENDING': {
      return {
        ...state,
        loading: true,
        errors: {}
      }
    }

    case 'FETCH_CONTACTS_REJECTED': {
      return {
        ...state,
        loading: false,
        errors: { global: action.payload.message }
      }
    }
}


The logic for action & reducer is done in one class in MobX. It uses OOP due to which the Store class is refactored to create multiple stores using the class constructor. The respective code is shown below:

@action
fetchAll = async() => {
  this.loading = true;
  this.errors = {};
  try {
    const response = await this.service.find({})
    runInAction('entities fetched', () => {
      this.entities = response.data;
      this.loading = false;
    });
  } catch(err) {
      this.handleErrors(err);
  }
}


So, we have seen that the logic defined in both state management solutions do the same job. The only difference is that we have used 33 lines of code in Redux and 14 lines of code in MobX to achieve the result. Hence, you can build apps faster with MobX.

Why use MobX for React apps?

MobX is a tested library that makes state management simple & scalable by applying functional reactive programming (TFRP) transparently. React and MobX is a powerful combination together.

  • Less Code to write
  • Easy to learn
  • Nested data is easy
  • Support for object-oriented programming


Why not use MobX?

  • Hard to debug
  • Better alternatives present
  • Gives too much freedom


Why use Redux for React apps?

Redux is a standalone library that can be used with UI framework including Angular, Vue, Ember, React & vanilla JS.

  • Extensibility via middlewares
  • Popularity & community
  • Tooling support
  • Predictability & simplicity
  • Unidirectional data flow & immutability
  • Separation of data & presentation


Why not use Redux?

  • Boilerplate (reducers, selectors, views, action types, action creators, …)
  • Actions are disconnected from their effect (as defined in the reducer)
  • No out-of-the-box solution for dealing with side effects (available via middlewares such as redux-thunk or redux-saga)


Final Note:

Now, you can see that the MobX code base is much more agile. Using OOP style and good development practices, you can quickly create React applications. The main disadvantage is that it is very easy to write poor code and impossible to maintain.

On the other hand, Redux is popular one and suitable for building large & complex projects. It is a strict framework with safeguards that ensures that each developer writes code that is easy to test and maintain. However, it is not suitable for small projects.

I hope I have provided enough information to clarify whether to migrate to MobX or continue with Redux. Ultimately, the decision depends on the type of project you are working on and the resources available to you.
Tags:
Hubs:
+1
Comments 0
Comments Leave a comment

Articles