Managing State

with mobx

Agenda

The Problem

Mobx Core concepts

Demo App

Redux vs Mobx

The Problem

Manage/Provide state across large and complex component tree

Solutions

Global state container/manger

---- with flavors ----

 

immutable  mutable

passive  reactive

dispatcher  pure function

Mobx

Anything that can be derived from the application state, should be derived. Automatically.

 

Core Concepts

Observable state

import { observable } from "mobx"

class Todo {
    id = Math.random();
    @observable title = "";
    @observable finished = false;
}
import { decorate, observable } from "mobx"

class Todo {
    id = Math.random();
    title = "";
    finished = false;
}
decorate(Todo, {
    title: observable,
    finished: observable
})

Computed Values

class TodoList {
    @observable todos = [];
    @computed get unfinishedTodoCount() {
        return this.todos.filter(todo => !todo.finished).length;
    }
}

Reactions

autorun(() => {
    console.log("Tasks left: " + todos.unfinishedTodoCount)
})

class MyResource {
    constructor() {
        when(
            // once...
            () => !this.isVisible,
            // ... then
            () => this.dispose()
        );
    }

    @computed get isVisible() {
        // indicate whether this item is visible
    }

    dispose() {
        // dispose
    }
}

Reactions

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

@observer
class TodoListView extends Component {
    render() {
        return <div>
            <ul>
                {this.props.todoList.todos.map(todo =>
                    <TodoView todo={todo} key={todo.id} />
                )}
            </ul>
            Tasks left: {this.props.todoList.unfinishedTodoCount}
        </div>
    }
}

const TodoView = observer(({todo}) =>
    <li>
        <input
            type="checkbox"
            checked={todo.finished}
            onClick={() => todo.finished = !todo.finished}
        />{todo.title}
    </li>
)

const store = new TodoList();
ReactDOM.render(<TodoListView todoList={store} />, document.getElementById('mount'));

Actions

class TodoStore {
  @observable todos = []

  @action addTodo = (title) => {
    this.todos.push(new Todo(title));
  }
  @action removeTodo = (id) => {
    this.todos.splice(this.todos.findIndex(todo => todo.id === id),1);
  }
  @action updateTodo = (id,newValue) => {
    this.todos.find(todo => todo.id === id).title = newValue;
  }
}

< VS >

MOBX

REDUX

< VS >

MOBX

REDUX

Multiple Stores

Reactive

Observable data structures

Nested state

Mutable

Automatically (tu)

Read/Write state

Impure

Optional Actions

Single Store

Passive

Plain Objects

Normalized state

Immutable

Manually (tu)

Read only state

Pure

Requires Actions