A simple introduction to state management with MobX in React Native

June 02, 2017 0 Comments

A simple introduction to state management with MobX in React Native

 

 

setState(..) is the most fundamental call in any RN Component. Often, you notice a pattern where child component’s state is derived from props received from parent component. This quickly becomes unmanageable once your application starts growing. Thats exactly solutions like Redux and MobX solve. There are bunch of articles and resources explaining the difference between these two fantastic solutions and their approach to solving state management.

If you have been a native developer on Android/iOS exploring RN, you sure are bound to know good deal of Object Oriented ways. This is where MobX shines, it has tremendous OO appeal. In this article we will explore the core concepts of MobX via a simple RN application.

Note: For in depth understanding you can follow this article and for a bit more involved RN example you can follow this one and this one. Also excellent documentation in MobX home page.

Here is a simple break down of main concepts

  1. Stores form your data sources. A store is basically a simple ES6 class. Eventually state is derived from data sources automagically by MobX through ES6 decorators.
  2. Store exposes observable fields, to which an observer reacts.
  3. Store additionally can expose derived observable fields as well. They are pure functions on observable fields. MobX calls them computed fields.
  4. Store can change values of observable fields via actions. This is the only way MobX allows you to change state.

Lets explore a simple CounterStore. It provides an observable field called count and actions increment and decrement to alter the value.

// @flow
import { observable, action } from "mobx";
export default class CounterStore {
  @observable count = 0;
  @action increment() {
this.count += 1;
}

@action decrement() {
this.count -= 1;
}
}

Here is a look at a component that observes count and re-renders every time count value is changed.

// RN imports
import { observer, inject } from "mobx-react";
@inject("counterStore")
@observer
class Counter extends Component {
render() {
return <Text>Count: {this.props.counterStore.count}</Text>;
}
}

By simply decorating class with @observer MobX infers reactions to store changes, auto magically subscribes to them and re renders the component on changes. @inject is MobX decorator that will provide component props with the mentioned store.

MobX provides a React Provider that can be setup as a parent component to all the components of your application. A MobX provider should be initialised with all the stores that you would want to be injected into your components.

import { Provider } from "mobx-react";
export default class App extends Component {
render() {
return (
<Provider {counterStore: new CounterStore(), userStore: new UserStore()}>
<Home />
</Provider>
);
}
}

Now all the children of Home component can be injected with counterStore and userStore.

Lets take a look at another example. A User Store that has observable fields for firstName, lastName, email, phone and fullName.

/* @flow */
import { observable, action, computed } from "mobx";
export default class UserStore {
@observable firstName = "Sen";
@observable lastName = "Appleseed";
@observable email = "send@appleseed.com";
@observable phone = "1155667788";

@action data(data: Object) {
if (data.firstName) {
this.firstName = data.firstName;
}
if (data.lastName) {
this.lastName = data.lastName;
}
if (data.email) {
this.email = data.email;
}
if (data.phone) {
this.phone = data.phone;
}
}

@computed get fullName(): string {
return ${this.firstName} ${this.lastName};
}
}

An interesting function is the fullName function. It is basically computed out of firstName and lastName observable fields.

MobX strongly encourages to keep the state information as minimal as possible and derive other state information with @computed get decorators that are pure functions of other observable fields.

@inject("userStore")
@observer
class FullName extends Component {
render() {
return <Text>FullName: {this.props.userStore.fullName}</Text>;
}
}

Whenever value for firstName or lastName changes fullName component is automatically re-rendered.

Thats it, utilising ES Next decorators, MobX auto magically handles subscriptions to observable fields and re renders required components. Plus the code looks so much better and readable.

Checkout the entire project on GitHub


Tag cloud