Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save katai5plate/b6bbf4f70312a2726114ee090aaa6435 to your computer and use it in GitHub Desktop.
Save katai5plate/b6bbf4f70312a2726114ee090aaa6435 to your computer and use it in GitHub Desktop.
日本語訳:MobX (with Decorators) in create-react-app

元記事

MobX (with Decorators) in create-react-app

デコレータと一緒にMobXをcreate-react-appで使う方法

MobXは、モダンアプリのステート管理に使います。
多くの場合、React.jsアプリに適用されますが、必ずしもReactにバインドされているわけではありません。
さらに、Reduxのステート管理ソリューションとして貴重な選択肢です。
create-react-appをボイラープレートとして使っている場合は、
MobXを設定する方法とcreate-react-appでデコレータを使う方法にぶつかります。
この記事では、create-react-appでデコレータを使用せず、MobXを使用するための重要な知識を提供します。

デコレータを使わずMobXをcreate-react-appで使う

基本的に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を使用するために必要不可欠なものです。

別の手段:create-react-app-mobx

GitHubにはMobXの開発者であるMichel Weststrateによってcreate-react-app-mobxが公開されています。
これはcreate-react-appにMobXがブートストラップアプリにインストールされています。
次のコマンドでインストールできます:

git clone git@github.com: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のデコレータではどうでしょう?

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でデコレータを使う4ステップ:

  1. create-react-appであなたのアプリをブートストラップした場合は、npm run ejectを実行します。
  2. 次のBabelプラグインをインストールします:npm install --save-dev babel-plugin-transform-decorators-legacy
  3. package.jsonに以下のBabel設定を追加する:
"babel": {
+ "plugins": [
+   "transform-decorators-legacy"
+ ],
  "presets": [
    "react-app"
  ]
},
  1. まだ次をインストールしてなければ、npm install --save mobx mobx-reactでインストールします。

これで、create-react-appで@アノテーションを使用できるようになります。
前の例では、ReactコンポーネントのMobXのローカルステート管理にデコレータを使用する方法を示しました。

デコレータ仕様時にejectを避けるには

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の代替手段を与えることは何も言い切れません。

ぜひ、あなたの次のサイドプロジェクトで試してみてください。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment