MobXはSimple, scalable state management
を謳うステート管理マネージャ。
最近Hacker NewsやEchoJSで、にわかにMobXがフィーチャーされている。
3 Reasons why I stopped using React.setState — Medium
この記事を読んで、そんなにいいもんかなと思い、試してみることにした。
mobxjs/mobx: Simple, scalable state management.
カウンター
簡単なカウンターを作ってみる。一秒で1インクリメンタルされるやつ。
import ReactDOM from "react-dom";
import React from "react";
import {observable} from "mobx";
import {observer} from 'mobx-react'
class AppState {
id = Math.random();
@observable counter = 0;
}
@observer
class App extends React.Component {
render() {
return <div className="app">{this.props.data.counter}</div>
}
}
const el = document.querySelector(".main");
const appState = new AppState();
ReactDOM.render(<App data={appState} />, el);
setInterval(() => {
appState.counter += 1;
}, 1000);
ステート側のリアクティブにしたいプロパティにmobx の@observable
デコレーターを付け、Reactのコンポーネント側にmobx-react の @observer
デコレーターを付与する。
あとはステート側を書き換えると変更が反映される。たぶんobserver ついたComponentのコンストラクタで observervable なプロパティの変更をフックして、高階コンポーネントのsetStateを呼び出してそう。(中身読んでないけど自分ならそう作るだろうなという予想)
Vueのデータバインダを思い出す感じもある。
@computed
他の値に依存する値を表現する
class AppState {
@observable counter = 0;
constructor(counter) {
this.counter = counter;
}
@computed get twice() {
return this.counter * 2;
}
}
@observer
class App extends React.Component {
render() {
return <div className="app">{this.props.data.twice}</div>
}
}
これで2倍表示されるようになった。
Becoming fully reactive: an in-depth explanation of MobX — Medium
@action
setState と違って値を1つずつ更新するため、非同期で複数更新すると、無駄にrenderが走ることになる。それを抑制するのがactionデコレータ。
class AppState {
@observable counter;
constructor() {
this.counter = 0;
}
@computed get twice() {
return this.counter * 2;
}
@action
incrementLazy() {
this.counter -= 1;
setTimeout(() => {
this.counter += 2;
}, 100);
}
}
@observer
class App extends React.Component {
render() {
return <div className="app">{this.props.data.twice}</div>
}
}
たとえばactionデコレータ を外すとこのような振る舞いになる。
デコレータがついてる場合は-1した部分がスキップされる。
(トランザクションの終了検知を実装するには、関数内部の静的解析が必要な気がするが、どうなってるんだろう?)
感想
デコレータでリアクティブプロパティーを作る部分は面白いが、入れ子のプロパティーを作ろうとするとasStructureという専用の構築子を要求されたりしだして、だるい感じ。正直トランザクション管理も自分でつくりだした沼にハマってるだけなので、別にsetStateでいい。
サンプルコード読んだり中身を想像する分には面白かった。
参考
tonyspiro/easy-mobx-example: Easy MobX + React Example https://github.com/tonyspiro/easy-mobx-example