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



    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.
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 0

    Only users with full accounts can post comments. Log in, please.