LoginSignup
4
3

More than 5 years have passed since last update.

Mobx + Statelessコンポーネントには、ストレスがない

Last updated at Posted at 2018-11-25

はじめに:Reactのstateはめんどくさい

stateには良いことが何一つない。

私はそう思っています。

stateは、

  • コンポーネントの作りが複雑であることを示している
  • テストがだるい
  • コンポーネント外からの参照がしづらい

と軽く挙げるだけでもデメリットがホイホイ出て来ます。

唯一かつ最大のメリットと思っているのは、
機能をコンポーネントで完結させられることだと思います。

これは配布や再利用にとても有効で、とにかく使いやすいと感じます。

Statelessなコンポーネントに変えよう

まずは簡単なStatefulなコンポーネント、
MyTextを用意しました。

See the Pen 9683c6b277428eccb652_1 by tsuuuuu_san (@tsuuuuu_san) on CodePen.

適当に入力してみてください。

コードを読めばティンときますが、
必須チェックと数値チェックが機能に入っています。

Statelessにしてみます。

See the Pen 9683c6b277428eccb652_2 by tsuuuuu_san (@tsuuuuu_san) on CodePen.

ロジックをMyStore classに移しただけじゃねーか!
ですって?

ちょっとそれは後にしてください。

先にこれを質問させてください。

MyTextのコードを見て!・・・使いやすそうですか?

多分大半の人は、使いづらそうと思っているのではないでしょうか。

本気だからこそ、Stateless Component

お気付きの方もいると思いますが
上記の一見使いづらそうなコンポーネントは、
自由度が飛躍的に向上 しています!

サンプルのerrorsに注目して見ましょう。

errorsはValidationの結果に応じて、メッセージが格納されます。

Statefulな場合、次の特徴があります。

  • 入力すると勝手に必須と数値チェックが走る
  • チェックの内容はerrorsに格納される
  • 初回Renderで必須エラーが出てしまう
  • つまり、これ単体で使いやすい

Statelessの場合、次の特徴があります。

  • 適切なpropsを設定しないと入力チェックは走らない
  • つまりこれ単体をポンと置いても望んだ動作は得られない
  • ただし、好きなValidationが入れられる
  • さらに好きなタイミングでValidationをかけられるように調整できる
  • つまり、自由度が高い
  • 自由度が高いので、急な仕様変更にも対応しやすい
  • HOCしてしまえば、Statefulな特徴を持ったコンポーネントも作れる

現場にもよりけりでしょうが、
Stateless化にメリットを感じる方も少なくはないのではないでしょうか。

Stateless化を推し進めると出てくる問題

結局のところ、データやロジックをどこかに寄せる問題が出てきます。
さらにStoreを取り入れていない場合、propsの伝搬を考えるのに一苦労です。

Mobxをご存知でしょうか

一言でいいますと、Storeです。

Reduxの複雑な手順を全て取っ払って、Storeだけにしたような感じです。

Mobxはその自由度がゆえに、ぶっちゃけ使いづらいです。

PJや要件などに合わせ、適切にStoreを設計しなければ、
破綻すること間違いなしです!

しかし・・

コンポーネントを操作しやすいように、
それに対応したStoreを用意するくらいなら、別に設計なんて必要ありません。

既存のStore設計の邪魔もしないでしょう。

MobxでコンポーネントにPropsStoreを与える

MobxStoreはどこからでも参照できます。

さらに、使い方は単純です。

  • Storeを作る
  • Storeをどこからでも呼べるようにRootコンポーネントにProviderを仕込む
  • 使いたいStoreをinjectして、Storeを参照する

だけです。

Stateless化を推し進めると出てくる問題 が解消されるでしょう。

例)コンポーネント用Store
import {observable, computed, action} from 'mobx';

export default class MyTextStore {
  /* MyTextのprops.valueにセットする */
  @observable
  value = '';

  /* MyTextのprops.onChangeにセットする */
  @action
  changeValue = value => {
    this.value = value;
  }

  /* MyTextのprops.errorsにセットする */
  @computed
  get errors() {
    const { value } = this;
    const errors = [];
    if (value === '') errors.push('必須だよ');
    if (isNaN(value)) errors.push('数字でお願い');
    this.setState({ value, errors });
    return errors;
  }
}

/*
※ Mobxよくわからない人向けの説明
@observableが付いていると、値に変更があった時にreRenderが走ります。
@actionが付いているものは、@observableな値を明示的に更新する関数です。
@computedは、@observableの変更に伴い、自動で計算されるものです。
*/

こんなStoreを作成して、コンポーネントにセットします。
(
 面白いのは、セット方法もこれまた自由なのがMobxクォリティ。
 すでにMobxStoreを用いているなら、そのStoreから参照できるようにしても良いですし、
 そのままinjectして、classプロパティをセットしてもいいでしょう。
 props用のObjectを作成する関数をStoreに用意しても良いですし、
 HOCを使うのもありかもしれません。
)

Stateless化 + MobxStoreのコンボは、Statelessコンポーネントのメリットを加速させます!

  • MobxStoreを用いることで、Stateを持っているかのような動作が可能になる
  • MobxStoreはどこからでも参照できます
    • Submitボタン押下で再Validation!なんかもできちゃう

外伝:MobxStoreは、どこまでも進化する!?

上記でMyTextに特化したMobxStoreの例を紹介しましたが、
これはあくまで一例にすぎません。

例えば、オブジェクト指向を併用すれば、
値やValidationはオブジェクトにロジックを寄せられるかもしれません。

コンポーネント単位でStoreを用意することが大変なら、
AtomicDesignの大きい単位で用意するのもありかもしれません。

なんてめんどくさい!Mobx!

しかし、より良いStoreの使い方を見つけた時のあなたの脳汁はきっとダバダバです。

最後に

Mobxを使おう!的な記事になったような気もしますが、そんなつもりはありません・・。

とにかくいいたかったのは、

極力Statelessコンポーネントを作ろう!
Mobx使うとStatelessコンポーネントも使いやすくなるよ!

ということです。

是非お試しあれ。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3