JS ? ReactNative × Redux ? ダサいよ... Flutter × Reduxにしましょう...

今回は初めて記事を書くことになりますが、よろしくおねがいします。私はiOSエンジニア（Swift）をやっていました。２ヶ月前あたりにはちょうどiOSとAndroid両方対応しないといけないプロジェクトを始めたのでいろいろを検討をしていました。最初はReact Nativeを検討していましたが、Expoがすごくよかったと思いますが、やっぱり自分はJSとフロントエンド開発には向いていないと思いますので、Nativeで両方iOSとAndroidを別々でやろうと思いました。TypeScriptをReact Nativeプロジェクトに入れようとしてもいろいろいじらないといけないのでめんどくさいなと思っていましいた。その時、ちょうど友人がちょっとFlutterをやってておすすめされました。Flutterをインストールして、VSCodeのPluginもよくできているので、FlutterとDart（言語的に）好きになりました。今回はタイトルと違って**FlutterでReduxを使った感想**を書きます。ReactNativeとかとは比較しません（笑）。

# Reduxとは？
私も最近までReduxを理解したばかりなので、おそらく私より説明できる記事はいくらでもあると思います。そちらの参考をおすすめします。今回は私が理解しているイメージを書きます（もし間違ったらコメントをいただければ助かります）。Flutterは各`StatefulWidget`は自分のデーターは自分で管理しています。Widget内のデーターの操作ももちろん、他のWidgetにデータを受け渡すや操作などはいろいろやっています。以下のようだいたいカオスになりやすいと思います。
<img width="454" alt="Screen Shot 2018-11-30 at 11.26.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/308866/d778d245-4ad6-dda0-bef1-edfbce8e3340.png">
Reduxの場合だとデーターの操作は一方通行になるので、綺麗になります。<img width="576" alt="Screen Shot 2018-11-30 at 11.26.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/308866/c6b4b3bf-16d8-dc77-11b3-ad28c649f04e.png">
データーと画面の状態（state）は全部Storeの中に入っています。そこでWidgetがStateを更新したい場合（ボタン押したらラベルが変わるなど）はActionをReducerにdispatchします。Reducerが現在のStateとActionを受け取って新しいStateを作成する。それが終わったら、Widget達がStoreのStateを参考して画面を更新するというフローになっているかと思います。

# なぜFlutterでReduxを使う?
ReduxはReactのUIのStateを管理する人気なフレームワークですがRedux自体はただの考え方なので、どこでも応用できます。SwiftだったらReSwiftでもちろんFlutterも`flutter_redux`というのもあります。下は私がReduxを使っていいと思ったことをリストアップします。

### 1. 全てのWidgetsはStatelessWidgetになると
<img width="505" alt="Screen Shot 2018-11-29 at 18.18.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/308866/768af6da-2f7d-c0cc-9374-b62fcf7d2ce2.png">
普通に`StatefulWidget`を実装する場合は画面を作成時にはWidgetの中のデーターを参考して作成しますが、`flutter_redux`の場合はデーターは全部`Store`内に管理しますので、

### 2. ロジックとビューの部分を完全分ける
#### 普通にStatefulWidgetを使う場合
<img width="397" alt="Screen Shot 2018-11-28 at 18.39.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/308866/325b9640-ecbc-41e6-87fb-5b3d78f2a2be.png">
普通のStatefulWidgetの場合はデーター、ビュー、ロジックは全部 `State`のクラスに書くのでコードが煩雑になりやすいです。分ける方法は別でいろいろあると思いますが（[MVVMとか](https://medium.com/flutter-community/easily-navigate-through-your-flutter-code-by-separating-view-and-view-model-240026191106)）。

#### flutter_reduxの場合
<img width="390" alt="Screen Shot 2018-11-28 at 18.39.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/308866/4903364d-7f07-6c81-e03d-499d107b575f.png">
`flutter_redux`を使う場合は`StatefulWidget`が`StatelessWidget`になって、データーは全部 `Store`に入れます。データーを操作したい時は`Action`をdispatchして、`Reducer`内でロジックを実装することになるのでかなり綺麗になります。

### 3. Redux Time Travelを前のStateに戻る
[Redux Time Travel](https://pub.dartlang.org/packages/flutter_redux_dev_tools)を使って前の状態とかに戻してDebugできます。

### 4. UIテストするのは簡単
私はまだUIテストはそんなにやっていませんので詳しくは言えませんが、Statesを作成して、画面ごとに渡せばUIテストはしやすいだと思います（ロジックとビューがちゃんと分けているので）。

# `flutter_redux`デメリット
これは`flutter_redux`の問題だけではなくて、基本Reduxの問題だと思いますが、かなりめんどくさいです。簡単なものをやりたいだけなのに、States, Actions, Reducersなどを作らないといけないのでファイル数が多くなりやすいです（ファイルを分ける場合）。


# よく使う `flutter_redux` の機能(Cheat Sheet)

私は記憶がよくないので、必要な時は毎回検索しないといけないので、一応はよく使われているものをメモをしてますので以下にリストアップします。

### WidgetをStoreに接続する
```dart
StoreConnector<AppState, ViewModel>(
  converter: (AppState store) => viewModel,
  builder: (BuildContext context, ViewModel viewModel) {
    return Text(viewMode.someRandomText)
  },
)
```
これを使ったら、この`StoreConnector`の下のWidgetsはstoreの状態を取れるようになります。Storeの`dispatch`も呼べるようになります。あとは `ViewModel`が変更されたら、`build()`が再起動されます。

### ActionをDispatchする
```
StoreProvider.of<AppState>(context).dispatch(MyRandomAction(value: 'Hello'));
```
これを使えば`context`内のどこでもActionを楽々dispatchできます。

### Storeの中のStateを取ってくる
```
final state = StoreProvider.of<AppState>(context).state;
final randomValue = state.myRandomValue
```
`StoreConnector`以外にもこれを使えば状態を取れます。

### まとめ
私的にはReactNativeをやった頃よりはReduxを好きになりました。最初の設定はかなりめんどくさい（State追加とかも）ですが最初からディレクトリを設計することでアプリの構成が綺麗になるかと思います。今回はMiddlewareまでは書く時間はなかったので、また時間を見つけて書きたいと思います。あとは他のFlutterのパターンも勉強してReduxを比較にしたいと考えております。