既存のReactアプリケーションにProvider
とinject
を使用してMobXの状態を注入する方法が公式で紹介されていますが、少しわかりにくかったので自分がやったことをまとめます。
非公式のチュートリアルに多く見られるようなstoreをまるごと全部ぶっこむような実装ではコンポーネントと状態が密結合すぎて落ち着かないので必要な要素だけinjectするようにします。MobXはそこを密結合にすることでReduxと比べて圧倒的に少ない記述量を可能にしているわけですが…。
1. storeを作成
~/stores/food.js
import { observable, action } from 'mobx';
class Counter {
@observable counter;
@action.bound
increment() {
this.counter++;
}
}
export default new Counter();
2. 既存のコンポーネントにProviderでstoreを提供
~/App.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'mobx-react';
import RootContainer from '~/containers/RootContainer'; // 既存のクラス
import counter from '~/stores/counter';
// たくさんのクラスにstoreを注入したい場合、こんな感じの関数を用意しておくと便利です。
function provideStore(Component, stores) {
return class extends React.Component {
render() {
return (
<Provider {...stores}>
<Component {...this.props}/>
</Provider>
);
}
};
}
const container = provideStore(RootContainer, { counter });
ReactDOM.render(
container,
document.getElementById('app')
);
3. Componentでstoreをinject
~/containers/RootContainer.jsx
import React from 'react';
import { observer, inject } from 'mobx-react';
// 必要な要素だけ選択的に注入
@inject(({ counter }) => ({
counter: counter.counter,
increment: counter.increment
}))
@observer
export default class RootContainer extends React.Component {
render() {
return (
<>
<div>{ this.props.counter }</div>
<button onClick={ this.props.increment }>Increment</button>
</>
);
}
}
所感
- どこにでもいきなりstoreをinjectできるので大規模なアプリケーションになるとしんどい
- せめてComponentにstoreの存在を意識させないために選択的にinjectを行うのが良さそう
- 小さいアプリを個人で作るときなんかはReduxのように丁寧にやるのは面倒くさくてしかたがないので、そういうときはMobXはかなり便利
- TypeScript導入できんのかこれ