🍃このブログは移転しました。
3秒後、自動的に移動します・・・。

0からはじめる MobX Part.4

さて、4回目です。
今回の目録はこちら。

  • computed
  • autorun

computed

Observableな値を定義するときにあわせて使う便利なやつです。
たとえば、こんな具合に。

const user = observable({
  firstName: 'Taro',
  lastName:  'Yamada',

  fullName: computed(() => {
    return `${this.firstName} ${this.lastName}`;
  }),
});

既存の値から`compute` = 計算して作る値ですね。
これがあると「本当に操作すべき値」とそうでない付随する値を明確に分けられるので良いです。

完了したTODOだけのリストとか、特定条件でフィルタしたリストとか、何もかも宣言的に書ける!

ちなみにDecoratorsを使ったクラスにするとこうなる。

class User {
  @observable firstName = 'Taro';
  @observable lastName  = 'Yamada';

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

// Non Decorators ver.
class User {
  constructor() {
    extendObservable(this, {
      firstName: 'Taro',
      lastName:  'Yamada',

      fullName: computed(() => {
        return `${this.firstName} ${this.lastName}`;
      }),
    })
  }
}

あと地味に書き方にパターンがあって、`extendObservable()`に引数なしの関数を定義すると`computed`な値として扱われたり、
ES5のGetterでも定義できたりします。(明示したいので使ってないけど

autorun

MobXのコア機能ですが今更の紹介に・・・!

// さっきのUser
const user = new User();

autorun(() => {
  console.log(user.lastName);
});

user.lastName = 'Sato';

// ↓ consoleのログ↓
// Yamada
// Sato

コードを見ればわかる通り、Observableな値の更新にフックしてコールバックされる仕組みです。
キモとしては初回実行されるところと、その初回実行時にアクセスされたプロパティの更新のみを監視するところ。

当たり前ですが上記の例で`user.firstName`を変更しても何も起きません。

var user = observable({
  name: 'leader22',
  age: 29
})

autorun(() => {
  console.log(user.name); // logged
})

user.name = 'foooo'; // logged
user = { name: 'bar', age: 10 }; // not logged

最後のがログに出ない理由がわかれば、もうMobXを制したようなものです!
(正解を言うと、再代入してる`user.name`は、`autorun()`内で最初にマークした`.name`とは違うから

詳しくはリファレンスを!

Understanding what MobX reacts to | MobX

これが使えるので、いわゆるViewは何を選んでもいいのです。
前に紹介した`mobx-react`の`observer()`も、この`autorun()`の拡張みたいなものって言うとピンとくるかな・・?

  • Observableな値をStateとして定義
    • その際に関連する値は`computed`で区別
  • `autorun()`でStateを更新する関数を定義
  • 然るべきタイミングで値を更新

これだけ覚えてればそれなりの規模のアプリは書けちゃう。