どのようなフェーズでReduxは求められるのか



※ この記事は、Simon Schwartzの[When do I know I’m ready for Redux? – DailyJS – Medium](https://medium.com/dailyjs/when-do-i-know-im-ready-for-redux-f34da253c85f)を翻訳した記事です。(もちろん非公式)

---

この記事では、Reduxを使い始めるべきか考える時にどのように考えるべきか私たちが見出した解決法や恩恵について書かれています。また、この話は[React](https://reactjs.org/)アプリを大きくしていくなかで学んだことに基づいています。

もし、stateやReduxについて知らないのであれば、あなたにとってあまり意味がない記事になるかもしれません。これらのコンセプトがあなたにとって新しいものであるかどうかを簡単に説明します。もし既にご存知の方は飛ばして進んでください。

### stateとは
stateは単なるデータです。ページが読み込まれていたり、ユーザーがログインしている場合は、stateは現在のユーザー名のようなデータの集まりと考えることができます。stateは、ユーザーの操作やAPIのレスポンスなどに応じて変更されうるものです。アプリはどのUIを表示するかを決めるためstateを読み取ります。

### Reduxとは
[Redux](http://redux.js.org/)は、アプリのstateを管理するためのツールです。Reactのアプリ開発においては非常に普及しているツールになります。

## なぜReduxを使うことにしたのか

> 早くに最適化することは諸悪の根源である - Donald Knuth

私がソフトウェアを構築しているときに従う格言があります。[Australian Broadcasting Corporation](https://developers.digital.abc.net.au/)の最新のReactアプリケーションを構築し始めたときに、ローカルなコンポーネントのstateを用いてアプリケーションのstateを管理することを選んだのは、以下が主な理由です。

最初の数週間はうまくいきましたが、多くの機能を私たちのアプリケーションに追加していくにつれ、stateの管理に関する問題が見えてきました。

私たちのアプリを通じてstateの変化を追っていくことは本当に難しくなりました。アプリケーションのstateを変更する関数は、いくつかのReactコンポーネントに散らばっていました。私たちのコンポーネントのいくつかは、stateを管理する機能により肥大化していました。それは、すべてにおいてちょいと面倒だったので、ソースコードはゆっくりと大きなスパゲッティボウルのように複雑になっていくように見えました。

![1_cpt28-LV83I-x6jQskDhSQ.gif](https://qiita-image-store.s3.amazonaws.com/0/124015/cb62322c-86ef-fdbc-5fdc-8ea8a0746505.gif "1_cpt28-LV83I-x6jQskDhSQ.gif")


このようにアプリを大きくしていった経験を通してお話ししましょう。

### 1日目
私たちはReactでローカルなコンポーネントのstateを使い始めました。Reactには「[unidirectional data flow](https://reactjs.org/docs/state-and-lifecycle.html#the-data-flows-down)」があります。コンポーネントがpropsとしてstateを下へと送るということです。上位レベルのコンポーネントにstateを設定し、データをpropsとして送信します。簡単です。

![1_O3-jbieSsxcQFkrTLp-1zw.gif](https://qiita-image-store.s3.amazonaws.com/0/124015/1f4d91d7-ba99-a4fe-9eb8-9b39473376c0.gif "1_O3-jbieSsxcQFkrTLp-1zw.gif")


### 5日目
いくつかの機能を追加しました。残念なことに、一部のコンポーネントはstateを共有する必要がありますが、親子関係は共有しません。

心配する必要はありません。私たちはこの問題を「[Lifting state](https://reactjs.org/docs/lifting-state-up.html)」で解決します。これは、state（およびstateを変更する関数）を最も近いancestor（Container Component）に持ち上げることを意味します。関数をContainer Componentにバインドし、それらをpropsとして下に渡します。子コンポーネントが親コンポーネントのstate変更を起こし、ツリー内の他のすべてのコンポーネントを更新することを意味します。いいね。

![1_DrxF4q1jNkiEKKm1EBAgiQ.gif](https://qiita-image-store.s3.amazonaws.com/0/124015/f9cec367-c92a-badf-95fe-347f23da3a9f.gif "1_DrxF4q1jNkiEKKm1EBAgiQ.gif")


### 20日目
いくつかの機能を追加し、アプリケーションのstateフローは次のようになりました

![1_9PS1G3FYqBbChVG0R1eh7Q.gif](https://qiita-image-store.s3.amazonaws.com/0/124015/b4f20d43-0397-abd0-b520-682cb2e57c2e.gif "1_9PS1G3FYqBbChVG0R1eh7Q.gif")


ご覧いただけるように、状態が更新され、アプリケーション全体に分散される方法はどんどん複雑になっています。アプリケーションの規模を拡大したときに感じ始めた主なツラい点は次のとおりです。

* コンポーネント構造はUIに基づいていた。だが、私たちのstateは必ずしも私たちのUI通りにはなっていない
* アプリケーション状態の形状は数多くのコンポーネントに広がっていた
* stateを変える関数は多くのコンポーネントに広がっていた
* アプリケーションのstateの全体像を知るためにはアプリケーション構造の「こうしたら、こうなる」といった頭の中のイメージが必要
* 私たちは同じpropsを複数のレベルのコンポーネントで渡していた
* アプリのデバッグ時にstateの変化を追跡するのが難しくなった

上記の問題のいくつかに直面している場合、Reduxが求められる可能性があります。

## Reduxはどのような動作をするのか
すべてのReactアプリケーションがReduxを使用する必要はないと言って始めましょう。実際、ほとんどの本当にシンプルなReactアプリケーションは、Reduxの恩恵を受けることはありません。

Reduxに関する最も一般的な不満は、それがかなり冗長であり理解に時間がかかることです。開発者は、actionとreducerを通じてアプリケーションのstateがどのように更新されるかを分かりやすく記述する必要があります。これにより、ローカルなコンポーネントのstateとしてではなく、単一のグローバルなストアとしてアプリケーションのstateを保持することができます。

以下、Reduxの構造を簡単に説明します。

### Action
actionとは、単にイベントに関する情報です。stateをReduxで更新する場合は、常にactionをdispatchすることから始めます。actionには、actionの名前と、必要に応じてactionとともに送信する必要のある情報を含める必要があります。actionがそのタイプを示す理由は、reducerがそれらを識別できるようにするためです。要するにactionとは、stateの変更を開始するイベントに関した静的な情報だけなのです。

### Reducer
actionがdispatchされると、actionがreducerに送信されます。reducerは、各actionがstoreをどのように更新するかを記述する純粋な関数(pure function)です。純粋な関数は、同じ入力を与えられたら常に同じ出力を返します。また、覚えておくべき重要なポイントは、reducerが常に新しいstateを返すことです。storeを直接変化させることはありません。

### Store
storeは、オブジェクトとして格納されているstateです。Reactコンポーネントはstoreに登録することができ、storeが更新されるたびにコンポーネントが更新されます。

ここにはその様子を表したものがあります。私は図の更新版を追加しましたが、今回はReduxを使用しています。

覚えておいてください：Reduxを用いてactionをdispatchし、Reducer関数をトリガーにすることでStoreを更新します。

![1_9PS1G3FYqBbChVG0R1eh7Q.gif](https://qiita-image-store.s3.amazonaws.com/0/124015/b9d58b39-b830-9330-8caf-7a11ce4fe460.gif "1_9PS1G3FYqBbChVG0R1eh7Q.gif")


## ここから何を学んだか
Reduxに乗り換えた後、以下のようなメリットがありました。

### Reactコンポーネントがシンプルに
* Reactコンポーネントの構造をフラット化し、いくつかのContainer Componentを削除することもできました。これは、データを下に渡す際にコンポーネントの階層を整理する必要がなくなったためです
* いくつかのClass ComponentをFunctional Componentに変換することができました

### 関心の分離(SoC)
* すべてのactionとreducer機能を記述したアプリケーションの明確なセクションで、新しい開発者がアプリケーションのビジネスロジックを一箇所で簡単に把握できるようになりました。
* Reactコンポーネントは、stateが肥大化しなくなり更新できるようになりました。これは、私たちのコンポーネントがUIの管理に集中でき、はるかに読みやすくなっていることを意味しています。

### 品質
* 特に[Redux logger](https://github.com/evgenyrodionov/redux-logger)を使ってstateをデバッグする方がずっと簡単でした
* Reduxで[ユニットテスト](http://redux.js.org/docs/recipes/WritingTests.html)を書くのは笑えるほど簡単です。

## 最後に

> 早くに最適化することは諸悪の根源である - Donald Knuth

この格言は今なお当てはまりますが、ほとんどのReactアプリケーションで早くにReduxを実装することが正しいアプローチだと考えています。私たちの経験から、ローカルなstateだけを使うのは面倒なことになります。

アプリが次の基準のいくつかを満たしているなら、すぐにReduxを実装するのが最善の方法だと思います。

* UIがstateに応じて大幅に異なる可能性がある
* stateは必ずしも線形で一方向に流れるとは限らない
* アプリを通した共通のユーザー体験に複数のstateの更新が必要
* 関係のない多くのコンポーネントが同じ方法でstateが更新される
* stateツリーが複雑
* stateは様々な方法で更新される
* 以前のユーザー操作を元に戻す必要がある

未だにあるコンポーネントについては、ローカルなstateを使用します。たとえば、多くのフォーム画面コンポーネントがありフォームの検証を処理する場合、現時点ではローカルなstateを使用して検証するのが最も効果的だと感じています。私たちがフォーム画面のローカルなstateを保持した理由はいくつかあります。

* コンポーネントのマウント解除後にフォームのstateを維持することは望ましくなかった
* フォームの検証stateはコンポーネントの外部で共有されることは決してなかった

### 始めてみたいですか？
Reduxを学ぶのに使った素晴らしい教材がいくつかあります。
* [Getting Started with Redux from @dan_abramov on @eggheadio](https://egghead.io/courses/getting-started-with-redux)
* [Read Me - Redux](https://redux.js.org/)
* [Leveling Up with React: Redux | CSS-Tricks](https://css-tricks.com/learning-react-redux/)

読んでくれてありがとうございます！
Dominik Wilkowskiに感謝します。

---
* この記事は、Simon Schwartzの[When do I know I’m ready for Redux? – DailyJS – Medium](https://medium.com/dailyjs/when-do-i-know-im-ready-for-redux-f34da253c85f)を翻訳した記事です。(もちろん非公式)

* 英語が特に得意な訳ではなく気合で訳してしまったものもあるので、フィードバックなども喜んでお待ちしています