MobX (with Decorators) in create-react-app
MobXは、モダンアプリのステート管理に使います。
多くの場合、React.jsアプリに適用されますが、必ずしもReactにバインドされているわけではありません。
さらに、Reduxのステート管理ソリューションとして貴重な選択肢です。
create-react-appをボイラープレートとして使っている場合は、
MobXを設定する方法とcreate-react-appでデコレータを使う方法にぶつかります。
この記事では、create-react-appでデコレータを使用せず、MobXを使用するための重要な知識を提供します。
基本的にcreate-react-appにデコレータの無いMobXを使用するのは簡単です。
コマンドラインでcreate-react-appを使ってアプリをスキャフォールしたら、
mobxとmobx-reactのインストールができるようになります:
npm install --save mobx mobx-react
前者はステート管理ソリューションとして使用され、後者はステート側をReactビュー側に接続するために使用されます。
これを使用し、ステートコンテナを作成したり、次のようにReactのローカル状態を使用せず、
ローカルコンポーネントのステートを利用することができます:
import React, { Component } from 'react';
import { extendObservable } from 'mobx';
import { observer } from 'mobx-react';
class App extends Component {
constructor() {
super();
extendObservable(this, {
counter: 0,
})
}
onIncrement = () => {
this.counter++;
}
onDecrement = () => {
this.counter--;
}
render() {
return (
<div>
{this.counter}
<button onClick={this.onIncrement} type="button">Increment</button>
<button onClick={this.onDecrement} type="button">Decrement</button>
</div>
);
}
}
export default observer(App);
extendObservable
は観測可能な値を作成しますが、
observer
は観測可能な値が変更された時にAppコンポーネントが反応することを確認します。
この反応は、コンポーネントの再レンダリングをもたらします。
結局の所、これはcreate-react-appでデコレータなしでMobXを使用するために必要不可欠なものです。
GitHubにはMobXの開発者であるMichel Weststrateによってcreate-react-app-mobxが公開されています。
これはcreate-react-appにMobXがブートストラップアプリにインストールされています。
次のコマンドでインストールできます:
git clone [email protected]:mobxjs/create-react-app-mobx.git
cd create-react-app-mobx
npm install
npm start
その後、ブラウザで実行中のアプリを見つける必要があります。
さらに、GitHubリポジトリではMobXを使用するためにプレーンなcreate-react-appをアップグレードするために、
使用できるgit patch commitを提供しています。
基本的にここまで示した全ては、デコレータなしでMobXを使用する方法です。
公式のMobXドキュメントも同様にそれを紹介しています。
誰かが「MobXを使うのにデコレータが必要だ」と言ったら、それは間違いです。
あなたはそれに対して、プレーンな関数を使うことができます。
では、なぜデコレータを使用するのでしょうか?
- ボイラープレートを最小限に抑える
- 宣言的
- 使いやすく読みやすい
- 人気
- まだネイティブではない(Babelを経由する必要がある)
- 不安定な仕様
MobXはデコレータを使用する唯一のライブラリというわけではありません。
むしろたくさんあり、それらの殆どは非デコレータソリューションを提供しています。
ですから両方のバリエーションを使用することができるのです。
MobXでは、両方の選択肢が次のようになります:
import React, { Component } from 'react';
import { observer } from 'mobx-react';
// デコレータを使わない場合
class App extends Component {
...
}
export default observer(App);
// デコレータを使う場合
@observer class App extends Component {
...
}
export default App;
@observer class App
を持つ変数定義のアノテーションは、Appが定義されている場合、observer(App)
と同じです。
そうすれば、再構成ライブラリから作成するなどのソリューションを使用して、
1つのコンポーネントに複数のデコレータを作ることができます。:
import React, { Component } from 'react';
import { observer, inject } from 'mobx-react';
import { compose } from 'recompose';
// デコレータを使わない場合
class App extends Component {
render() {
const { foo } = this.props;
...
}
}
export default compose(
observer,
inject('foo')
)(App);
// デコレータを使う場合
@inject('foo') @observer
class App extends Component {
render() {
const { foo } = this.props;
...
}
}
export default App;
では、Reactとcreate-react-appのデコレータではどうでしょう?
現状、Babelが安定した段階でそれらをサポートするまで、create-react-appのメンテナーがデコレータを保持しています。
私達のポジションは単純です: async/awaitのように十分安定しているか、Facebookが頻繁に使う変換(クラスプロパティ)を追加します。 標準で何か変更があった場合は、それらから離れて移行するためのコードサンプルを作成してリリースする予定です。 (related issues 1 & 2)
しかし、もしあなたのcreate-react-app + MobXアプリにデコレータを使用したい場合は、どうしたら?
import React, { Component } from 'react';
import { observable } from 'mobx';
import { observer } from 'mobx-react';
@observer
class App extends Component {
@observable counter = 0;
onIncrement = () => {
this.counter++;
}
onDecrement = () => {
this.counter--;
}
render() {
return (
<div>
{this.counter}
<button onClick={this.onIncrement} type="button">Increment</button>
<button onClick={this.onDecrement} type="button">Decrement</button>
</div>
);
}
}
export default App;
プレーンなcreate-react-appでこのコードを実行すると、Unexpected token
エラーが発生しますので、
Babelの設定にデコレータを追加する必要があります。
しかし、create-react-appではBabelの設定にアクセスすることはできません。
アクセスする方法は一つだけあります。
- create-react-appであなたのアプリをブートストラップした場合は、
npm run eject
を実行します。 - 次のBabelプラグインをインストールします:
npm install --save-dev babel-plugin-transform-decorators-legacy
- package.jsonに以下のBabel設定を追加する:
"babel": {
+ "plugins": [
+ "transform-decorators-legacy"
+ ],
"presets": [
"react-app"
]
},
- まだ次をインストールしてなければ、
npm install --save mobx mobx-react
でインストールします。
これで、create-react-appで@アノテーションを使用できるようになります。
前の例では、ReactコンポーネントのMobXのローカルステート管理にデコレータを使用する方法を示しました。
GitHubには、アプリケーションのejectを避けるため、
create-react-appのcustom-react-scriptsが入ったフォークがあります。
それを設定するには、GitHubリポジトリの指示に従ってください。
なぜなら今後、変化するかもしれないからです。
さらに、.babelrcファイルにアクセスし、Next.jsアプリでBabelを設定する事ができます。
新しくブートストラップされたNext.jsアプリでは、
これらの2ステップでデコレータを使用してMobXを有効にします。
まず、プロジェクトにMobXの依存関係とデコレータの移行をインストールします。
npm install --save mobx mobx-react
npm install --save-dev babel-plugin-transform-decorators-legacy
次に、プロジェクトのルートにある.babelrcファイルにデコレータサポートを追加します
{
"presets": [
"next/babel"
],
"plugins": [
"transform-decorators-legacy"
]
}
結局の所、選ぶのはあなた次第です。
Next.jsをMobXのサンプルプロジェクトでクローンするか、
デコレータの有無に応じて独自にMobXを追加できます。
単純なReact、create-react-appまたはNext.jsアプリでデコレータの有無に関わらずMobXを使用した後、
MobXにReduxの代替手段を与えることは何も言い切れません。
ぜひ、あなたの次のサイドプロジェクトで試してみてください。