ReactNativeとTypeScriptでDucksデザインパターンを試してみた

Reduxのディレクトリ構成の一つにDucksというデザインパターンがあるみたいで、けっこう良さそうなので採用してみました。  

以下の例ではドメインをpage1,page2と分けています。
ドメインというのは、まとまりのある機能ごとのページのようなものです。
LINEアプリで言えば、page1が「友だちのページ」、page2が「トークのページ」のようなイメージです。  

一般的なディレクトリ構成

一般的なReduxのディレクトリ構成では、まずreducersactionsというディレクトリを作って、その中にドメインごとに分けたファイルを作ります。

また、それぞれのディレクトリの中にルート的な存在になるindex.tsなるファイルがあったりもします。 この中では例えばreudecers/index.tsの場合は、combineReducers()で各々のreducerをまとめたりしています。  

これのどこが問題なの?

このようなディレクトリ構成の場合は、ドメインが増えていくたびに複数の箇所でファイルを追加しなければならなかったり、 単純にファイル数が増えるので保守性に欠けるという問題が生じてきます。  

Ducksのディレクトリ構成

 そこで、このような問題を解決するためにDucksというディレクトリ構成を採用してみました。
以下のようになります。

こんな感じにactionTypes,actions,reducesをドメインごとにmodules/hogeModule.tsのような、同じファイルの中に書いてしまいます。

1ファイルの行数は増えてしまいますが、密結合であるこれらは同じ場所にまとめてしまったほうが管理しやすくなるかと思われます。

今回は書いていませんが、middlewareのsagaなどもこのmodulesの中に書きます。  

なんのためにやるのか、メリットは?

少し上述しましたが、

  • 関心事ごとにわけられる
  • ファイル数が減り、見栄えが良くなる
  • 管理しやすくなる

等が挙げられると思います。

これを知ると逆になんで今までわざわざファイルを分割してたの?って気にもなりました。
テストに関しては今までどおり、部分ごとに書けるので特に影響はなさそうです。  

デメリット

強いてあげるとすれば、 modules内の1ファイルの中の行数が増えることかなと思います。

しかし、可読性は損なわれないと思うので、メリットを享受できる方が大きいかなと思います。  

Ducksのルールについて

このページにDucksのルールが書かれていたので、引用します。

  1. reducer()にはeport defaultを付けましょう
  2. ActionCreatorたちにはexportを付けましょう
  3. ActionTypesはAppName/ReducerName/ACTION_TYPEの形で名付けること
  4. ActionTypesを外部で利用したりする場合は、UPPER_SNAKE_CASEとしてexportできる(よくわからん)

3に関しては、プロジェクト全体でのActionTypesがユニークになるようにするためのなのでしょうか。
僕の環境ではなぜか、これ通りにすると動かなかったので、ひとまず今までどおりACTION_TYPESだけの命名にしました。  

実際にやってみた

今回は最小のReduxアプリということで、 ボタンを押したら表示されている文章が変わるだけのアプリを作ってみました。

フォーマット

さっそくファイルの中身を見ていきます。 登場人物は主に3つです。 modulesとsotreとcontainerです。  

modules/MainPageModule.ts

上述したルールの通り、Reducerに関してはexport defaultし、 その他、外部でも使うものにはexport宣言をしています。
今まで分離させていた、action typesactionreducerを一つにファイルに書いてます。  

store

従来のものと異なる部分は、このstoreの中でcombineReducerを用いて、複数の(この例では一つですが)reducerを連結してしまうことです。
従来のものではreducers/index.tsなどにルート的なReducerを定義していましたが、Ducksにすることでこのファイルが消えるので、store内でcombineReducerを実行することになります。  

container

がんばって型を書きまくっているので、少しごちゃごちゃしていますが、これに関しては従来のものと大差ありません。

余談ですが、Ducksを採用しているプロジェクトをGitHubで漁っているとデコレータでconnectしているものが多かったので、使ってみました。

スタイリッシュですね///  

containerの数だけmodulesを作るの?

アプリの設計にも依ると思いますが、イメージ的には

  • container componentの数だけ
  • atomic designのpagesの数だけ

作ることになるのかなという感じがしていますが、 複雑になってくるともう少し工夫が必要になるかもしれません。  

ファイルの命名はどうしよう

結構悩むのが命名ですね。

この記事では紹介していませんが、Reduxと関連していないコンポーネント群はAtomicDesignで構成しています。

この構成でいくとドメインごとの一番親にpagesというContainerComponentsが入るディレクトリがあり、 そのファイルの命名をHogePageとしているので、 今はそれに倣ってHogePageModuleと名付けてみました。

良いのかどうかはさておき、まぁ、わかるかな、という感じです。
また良さげのものを思いついたり見つけたりしたら紹介したいと思います。  

参考

とても詳しくてわかりやすかったです。
型定義などについてもめちゃくちゃ参考にさせていただきました。ありがとうございます。

【参考】React + Redux + TypeScriptの最小構成 – Qiita