MobX の runInAction とは

故あって、React + MobX なプログラムを読んでいたら、

runInAction(() => {
  this.state = "done";
});

といった runInAction の呼び出しを多く見かけて、なんだろこれ、と思ったのでメモ。MobX 1日目で変なこと書いているかもしれません。

Writing async actions | MobX を順に読んでいけば分かるのだけど、

  • MobX では strict mode を有効にすることで Action 外で state を変更しようとしたらエラーにすることができる
  • ↑の制約を設けた場合、Action で呼び出した非同期処理のコールバックがただの無名関数だと Action 外ということになるので、コールバックにはメソッドとして定義したアクションを指定する必要がある
  • とはいえ、コールバックのためだけにメソッドを定義するのもまわりくどいので、無名関数を Action にできるユーティリティ関数が用意されている
  • さらに TypeScript で書いている場合に、↑だとコールバックの引数の型を都度記述する必要があって面倒なので、最後の state の変更だけを無名関数に切り出して、アクション内として呼ぶためのユーティリティ関数が用意されている。それが runInAction

ということだった(なんか問題を解決しようとして、さらに問題を生んでを繰り返していて、複雑...)。Action 内の非同期処理のコールバックで state を変更する場合はとりあえず runInAction 経由でおこなえばとりあえずは動く。

Vuex の場合は副作用の伴う処理は Action, state の変更は Mutation で役割が分かれていたのだけど、MobX の Action は副作用の伴う処理も state の変更のいずれも Action 内でおこなうことができる。ただ、「できる」というだけであって、Vuex のように副作用の伴う処理と state の変更で分離する設計をしてもよい。
個人的には副作用が伴う処理とそうでない処理が明確に分かれていたほうが見通しが良いし、書く時に迷わないので、多少は面倒だけども、メソッドをアクションとして定義して、それをコールバックに指定する形で分けると思う。