🧊

Next Generation State Mangement by @mweststrate in #ReactEurope の日本語メモ

ReactEurope 2017のDay2より。

動画とスライドのリンクはこちらから。

ReactEurope 2017 Day 2 AM - YouTube / slides

MobXのサブプロジェクトみたいな存在である`mobx-state-tree`についてのトークです。

`mobx-state-tree`とは

本編はもちろんMobXについては知ってる前提 + `mobx-state-tree`のREADMEくらいは眺めてふんふんって感じじゃないと辛いかも・・って感じなので、さくっと紹介。

GitHub - mobxjs/mobx-state-tree: Opinionated, transactional, MobX powered state container

MobXを使う場合、アーキテクチャは特に指定がない。
その分だけ柔軟で、ボイラープレート的なコードも不要で書き味が良い!っていうメリットがある反面、やっぱりスケールさせるならルールが必要でしょ!考えればいいっちゃ良いけど、なんかお手本的なコードとか仕組みとかあった方が嬉しいよねーっていうのもあり。

そこで作者のMichelが目下やってるプロジェクトがコレです。

本編メモ

MobX vs Redux

  • この観点も悪くないが、いいとこどりできればより良い
  • それぞれ表すなら
    • Mutable Model Graph -> MobX
    • Immutable Tree -> Redux
    • どちらもメリットとデメリットがある
  • そこでいいとこどりの`mobx-state-tree`!
  • 以下、メインの機能の紹介

Snapshots

  • 良いよねー
  • Reduxだと、Stateのツリーがそのまま使える
  • MobXだと、`computed`でそれ用の関数をModelに生やせばいい
    • ただそれだとボイラープレートなコードがどうしても必要になる・・
  • `mobx-state-tree`だと、`getSnapshot()` / `onSnapshot()` / `applySnapShot()`ってのが用意されてる

TypeChecks

  • ランタイムの型チェックができるようになってる
    • どのモデルがどういう型か
    • エラーになったなら何をどうしようとしたかがわかる

そもそも、Modelの定義をこれでやる。

import { types } from "mobx-state-tree"

const Todo = types.model("Todo", {
    title: types.string,
    done: false
}, {
    toggle() {
        this.done = !this.done
    }
})

const Store = types.model("Store", {
    todos: types.array(Todo)
})

みたいな。

JSON patch

  • http://jsonpatch.com/
  • どういう処理がツリーに対して行われたか残る
    • `add` / `replace` / 'remove'
  • サーバーサイドから他の人の変更差分をもらって反映・・とか

Actions

  • ダイレクトな値の更新を禁止する
  • ツリーのどの部分に対してどういう変更をしたか残る
  • 更新できるのは自身とそのサブツリーのみ
  • Actionも記録されるのでリプレイもできる
    • `clone()`したデータに対しても同じく
  • `middleware`をかますこともできる

値の参照の問題

  • Mutableだと次の行で参照先が変わってる可能性がある
    • Immutableだとその心配はない
  • これもSnapshotを使って解決できる
  • モデルどうしの参照でも有用な概念

所感

  • ImmutableとMutableの狭間でどう生きてくか・・は確かに課題感があったのでおもしろかった
  • ただちょっとOpinionated過ぎるかなーという気もする
    • MobXを完璧に把握してないと旨味を味わう前に挫折しそう
    • てか、こういうのが必要 = Reduxでやれ案件な気もする
  • MobXやる上でSnapshotのアイデアはすごくよい
    • Model間での参照、連携問題は確かに悩んでた
    • 個別に`toJS()`するのも面倒やなーと思ってた
  • ちなみにReduxのインテグレーションあるんやでまじやで