2020-6-29
Container/Presentational Component
(追記:2021-07-15)このパターンは React においては自分は採用しないことにしようと思う
理由は以下2点より。
- UI とロジックの分離に関しては Hook でやるべき
- テスト容易性の確保に関しては、そもそもコンポーネント単位でテストすることが(自分は)無いのに、それを確保するためにコードの見通しを悪くすることが微妙に感じるようになった
UI とロジックの分離に関しては Hook でやるべき
Container/Presentational パターンは、dan_abramov 氏が提唱したしたもので、目的は UI とロジックの分離だった。
当時はクラスコンポーネントの時代で、状態を弄くり回すコードをクラス外に出すことが出来なかった。なので、状態をいじくり回すコンポーネント(Container コンポーネント)と UI(Presentational コンポーネント)を分けようねっていう話が提唱された。
今は Hook があることで、コンポーネントを分けること無く状態に関するロジックを切り出すことが出来るよねっていう話。
テスト容易性の確保
僕個人としては、テスト容易性の担保の手段としてこのパターンが好きだった。いわゆる DI 的な使い方をする感じ。Container コンポーネントで依存を解決して、Presentational コンポーネントは完全に見た目だけに責務を持つようにし、単体テストを容易にするという感じ。
で、確かにテストは容易になるんだけど、実際の所コンポーネントの単体テストをするかというと僕個人としてはあまりしなかった。
テスト容易性に関する恩恵が事実上ない割に、本来必要ないはずのバケツリレーが大量に発生しコードの見通しが悪くなる事が多くなった。どうせ自動テストしないんだったらもう分けないほうが開発効率上がるのでは?という気持ちが正直今は大きい。
念の為書いておくと、バケツリレー解消のために Redux 使おうという話ではなく、本来不要なバケツリレーは無いほうが見通しいいよねっていう話。
概要
-
Presentational Component
- 見た目に責任を持つ
- データやコールバックは props として受け取る
- state は自身の見た目に関わる物以外持たない
- スタイルを持つ
-
Container Component
- データに責任を持つ
- データやコールバックを PresentationalComponent に props 経由で渡す
- stateful
- スタイルを持たない
カテゴリ分けの目的
- コード分割の指針
- テスタビリティの確保
- テストを阻害するデータ操作を Container Component へ追いやることで、Presentational Component のユニットテストを容易にする
- じゃあ Container Component は?って話に関しては Container Component に対してユニットテストをするのではなく、呼び出している関数に対してユニットテストをすればいい
- テストを阻害するデータ操作を Container Component へ追いやることで、Presentational Component のユニットテストを容易にする
Presentational 内に Container を入れることの是非
自分の結論として、「children 等 props 経由」なら Presentational Component 内に Container Component が存在しても良い。直書きはだめ。
なぜ props 経由かと言うと、直書きしてしまうと Presentational Component が Container Component の機能を内包することになってしまい原則が崩れてしまうため。テストする時にも Container Component の存在が邪魔になってしまう。
DI のように、props 経由で外部から注入するようにする。注入する箇所は更に外の Container Component となる。