umma.dev

MobX to Redux

MobX enables you to cut out a lot of code that is used in Redux however Redux is a popular choice for state management.

How MobX Works

Observables

Using the @observable decorator and extending data structures such as objects, arrays and classes, this defines application state the component has access to.

import { observable } from 'mobx'

class Example {
    @observable test = true;
}

...

class ExampleComp {
    @observable examples = []

    @computed
    get theExample() {
        return this.examples.filter(example => example.test).length
    }
}

In the example above the value for test refers to an array. The @computed decorator enables values to be derived automatically when the value is modified.

The Store

The store allows current state to be modified.

import { observable, action, computed } from 'mobx'

class ExampleStore{
    @observable examples = []

    @action
    addExample = example => {
        this.example.push(examples)
    }

    @computed
    get examples() {
        return this.examples.length
    }
}

Actions

Actions allow you to change the state. Also note, stores are injected into components.

import React, { Component } from 'react'
import { inject, observer } from 'mobx-react'

@inject('ExampleStore')
@observer
export default class extends Component {
    render() {
        return (
            <>
                <p>{this.props.ExampleStore.examples}
            </>
        )
    }
}

How Redux Works

There are three main features of Redux; the store, reducers and actions.

The Store

The state of the application lives inside the store. The store contains the main rootReducer. Within the reducer folder you are likely to have many reducers that are all pulled through the rootReducer file, as shown below.

import { combineReducers } from 'redux'
import dataReducer from './dataReducer'

export default combineReducers({
	dataReducer
})

Redux uses pure functions, this means it’s difficult to manipulate data with functionality such as API requests. To get around this you can use a middleware. In Redux you have two options redux-saga and redux-thunk.

import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import rootReducer from './reducers/'

export default function configureStore() {
	return createStore(rootReducer, applyMiddleware(thunk))
}

Reducers

The state returns from the reducers. In Redux state cannot be changed unlike within a component which can be changed with setState. The reducer is a function which takes in the state and action.

export default(state = {}, action => {
    switch(action.type) {
        case 'THE_TEST':
            return {
                ...state,
                test: action.payload
            }
        default:
            return state
    }
})

Actions

Actions are objects which enable the the reducer to understand when to set the next state; through a signal to the store via an action, usually known as dispatching an action.

import { THE_TEST } from './types'

export const theTest = (payload) => {
    return {
        type: THE_TEST,
        payload
    }
}

export const getTest = () => {
    return function(dispatch) {
        dispatch(theTest())
    }
}
//types file
export const THE_TEST = 'THE_TEST'

Switching MobX Features to Redux

  • When setting up Redux, ensure there is a store, reducers and actions. In MobX the store will be very similar.

  • Create all reducers you will need for your application. Usually this will be in the form of observables.

  • Create a types files for all actions and create actions for all corresponding reducers

  • Ensure the store has a middleware