React Native Mobx Tutorial - Part 1

MobX is state management solution that is gaining popularity very fast. I’ll show you how to create a simple React-Native app using MobX.

What Are We Going To Build

I have a few crypto coins on some exchanges. Not like I’m trading or something, I just bought some tokens that I liked and now just hold them and buy/sell occasionally.

On Binance you can see how many coins you have and what’s their worth in bitcoin and even in dollars, but you can’t see what’s the difference since the last time you’ve checked it.

We are going to build portfolio tracker for it. On first run we’ll save all the coins prices and then we’ll show the difference.

It’ll look somewhat like this:

binance tracker

We’ll learn how to store data locally, use flatlist, navigator and do multi-screen applications, also we’ll learn how to manage state using MobX.

Table Of Contents

  1. What is MobX
  2. Making ReactNative app
  3. Testing stores
  4. Testing views with Enzyme

Why MobX?

MobX is usually faster than Redux, requires less boilerplate and in general it’s easier to grasp for novice.

MobX has very few core concepts:

Observables

Observables allow you to subscribe for their changes. You can annotate your class properties with @observable decorator and then track their values with observers. So every time the values will change – observers will be updated accordingly.

Here is simple example. It’s a rolling dice – every time you press ROLL button – it re-rolls the dice and displays resulting number from 1 to 6.

import React, { Component } from 'react'
import ReactDOM from 'react-dom';
import { observable } from 'mobx';
import { observer } from 'mobx-react';

@observer class Dice extends Component {
  @observable value = 1;

  render() {
    return (
      <div style={this.styles.container}>
        <div style={this.styles.result}>Result: {this.value}</div>
        <button onClick={this.handleRoll}>ROLL</button>
      </div>
    )
  }

  handleRoll = () => {
    this.value = Math.floor(Math.random()*6) + 1;
  }

  styles = {
    container: {
      padding: '16px 0px'
    },
    result: {
      fontSize: 22,
      marginBottom: 10
    }
  }
}
ReactDOM.render(<Dice />, document.getElementById('dice'));

Computed values

Computed values can be derived from observables and will be updated automatically when the latter will be changed. Keep in mind, that in order to be updated computed has to be observed.

@computed get computedValue() {
  return this.value > 3 ? 'WIN' : 'LOOSE'
}

render() {
  return (
    <div style={this.styles.container}>
      <div style={this.styles.result}>Result: {this.value}</div>
      <div style={this.styles.result}>Computed Result: {this.computedValue}</div>
      <button onClick={this.handleRoll}>ROLL</button>
    </div>
  )
}

Reactions

Reactions are very similar to computed values but instead of returning new value they are used to produce side-effects (making network requests, patching DOM etc.)

MobX provides 3 types of reaction functions when, autorun and reaction

  • when accepts two functions: predicate and effect. It runs and observes predicate until it returns true, and then runs the effect function. After that it disposes, and stops reacting observed property.
  • autorun is for cases when you need reactive function that will fire every time the observed value is updated. Unlike computed it doesn’t have to be observed itself.
  • reaction is like autorun but gives you more control over what properties to observe. It accepts two functions data-function and side-effect-function. data-function is tracked and returns data that is used in side-effect-function.

Here is an example of autorun:

constructor() {
  super();
  autorun(
    ()=> (this.value > 3) && alert('WIN')
  )
}

Actions

Actions are anything that alters the state. So you can use them to explicitly mark that functions with @action decorator.

This decorator takes function and wraps it into transaction, untracked and allowStateChanges.

  • transaction is used to batch state updates so no observers will be notified until that function is completed. So you can update multiple properties at once.
  • untracked allows you to run code without establishing observers (just like reactions, or unlike computed’s)
  • allowStateChanges is used to allow/disallow state changes for certain function. By default allows action to make changes (and disallows for computed and observer).

Observers

Strictly speaking observers aren’t part of MobX core. They are provided by the mobx-react package. But anyway…

They are used to make your views “observe” observables and re-render on change.

But I’ll cover it in next part.