Reduxを完全に理解した(〜理論編〜)

Reactで個人開発をしていた時に、めんどくさい壁にぶち当たったことはありませんか？
めんどくさい壁はいろいろありますが、その中でも私はバケツリレー形式で各コンポーネントにデータを渡すのがすごい手間でした:joy:。
それを解決してくれるReduxについて説明していきたいと思います。

# Reduxとは
2015年に公開されたJavascriptライブラリで、Javascriptで構築された「**アプリケーションの状態をうまく管理する**ためのもの」と捉えてもらえば良いです。

:::note info
簡単に言えばデータを一元管理でき、各コンポーネントからそのデータを参照・更新ができるみたいなものです。
:::


# 何故Reduxは生まれたのか
- SPA(React, Vue.js, AngularJS)を構築する上で、アプリ全体の状態管理をすることが難しかった。
- SPAではアプリの状態は特定の変数に関連付けられているが、「いつ、どこで、どのように変化した？」がうまく捉えられない。

⇒これらを解決するためRedux登場

# Reduxを使うメリット
Reduxを使う場面はSPAで使う場面が9割9分だと思いますが、SPAでもしReduxを導入しなかった場合と導入していた場合を比較してメリットを伝えます。

### :sob:Reduxを導入していなかったら
親で持っているデータを子コンポーネントで使いたい場合、バケツリレーのようにデータを渡し続ける必要がある。
これをやったことがある人は分かると思いますが、大変めんどくさいです。
また、これはアプリケーションの規模が大きければ大きいほど影響も大きくなります。
<img width="500px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516848/80532b71-9bf3-70d6-8ffc-f591bc82763f.png">


### :grin:Reduxを導入していたら
Reduxを導入していなかった場合と同じく、親コンポーネントのデータを子コンポーネントから呼び出したい時に、親のデータをStoreというデータを一元管理する場所に格納しておくことで、子コンポーネントはStoreからデータを取ってくるだけで済むので、あの地獄のバケツリレーもしなくて良いのはすごく嬉しい:laughing:。

<img width="500px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516848/d48727a5-3d85-a1b6-2a59-d57e7e93c9e3.png">


# Reduxの三原則
Reduxには三原則があり、必ずこれを満たさなければなりません。
### :one:***Single source of truth***
アプリケーションの状態をたった1つの「**Store**」で管理すること。

### :two: ***State is read-only***
アプリケーションの状態に変化を加える時は、必ず「**Action**」を「**Reducers**」に送信する必要がある。
（状態は読み取り専用）

### :three: ***Changes are made with pure functions***
状態変化は純粋関数によって行わなければならない。
⇒「**Reducers**」は現在の状態に変更を加えるのではなく、新しい状態を返す

# **Store**？, **Reducer**？, **Action**？
ここで上で出てきた３つの単語「Store」、「Reducer」、「Action」について説明します。

### Store
アプリケーションの状態を保持するオブジェクトのこと。
ReactなどのフレームワークからStoreを参照することでUIにStoreを反映させることができる。


### Reducer
Reducerは元の状態を変更することなく、新しい状態を返す。
⇒純粋関数

状態変化を生じさせるためには、ActionをReducerへ送信する必要がある。
また、ReducerにActionを送信する動作をDispatchと呼ぶ。

### Action
個々のイベントに対する情報のこと。
例えば、データを追加、更新、削除
Reduxでは状態変化をすべてActionを介して行う。


# Reduxの流れ
言葉で色々説明しましたが、あんまりピンとこないと思いますので、図を使って説明していきます。
ここでは簡易家計簿アプリを例にします。

<img width="300px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516848/da55f41d-92b9-11db-04dc-2db12fa39a76.png">

これは+100円ボタンをクリックすると0円→100円に変更され、-100円ボタンをクリックすると0円→-100円に変更されるというアプリです。

#### 初期状態
まず、この初期状態の0円という情報については、これも「**Store**」からのデータを反映しています。
<img width="500px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516848/ca3a7b29-8700-2632-0f4d-029655a1c6dd.png" /> 

#### +100円ボタンをクリック
それでは+100円ボタンをクリックした時に、UIへ100円と反映されるまでの流れについて説明します。
+100円ボタンを押すとEvent Handler内で「Action」を生成します。
<img width="500px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516848/5e3846ee-b377-d480-01e2-804ba1760b8a.png" />

その後、「**Dispatch**」して「**Reducer**」に「**Action**」を渡します。さらに、現状の金額を「**State(状態)**」から取ってきて計算します。
<img width="500px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516848/e7705425-a2e1-7fcc-6805-a1b8715447e7.png" />

Reducerで計算した結果、100円となり新しく「**State(状態)**」を返します。
※0円が入っていた古い「**State(状態)**」はなくなります。
<img width="500px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516848/738ae9ee-536c-e48c-9636-977f91fcce72.png" />

新しく生成されたStateの情報を元に、UIを反映します。
<img width="500px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516848/c153c4be-6333-3aff-50be-5c805acab316.png" /> 

これで完了です。
-100の場合はActionの中身が以下の通りとなり、Reducerの計算が減算に変わるだけです。
```
{
  type: withdraw,
  payload: 100
}
```

# まとめ
なんでこんなにめんどくさそうなことしなくちゃいけないんだと思われるかもしれませんが、今回の例だとコンポーネントに分ける必要もないくらいの超簡易アプリなのですが、コンポーネントがたくさん作られているアプリケーションだと恩恵を受けます。

これを実装するとなるとまた大変なのですが、実装編を以下執筆していますのでぜひご覧になってください。
[Reduxを完全に理解した(〜実装編〜)](https://qiita.com/kzy83/items/55276dbdaeb74718ae28)

チーム開発でReactやVue.jsなどSPAを使っている開発現場では、Reduxがほぼ100%必要になるので、ぜひこの記事を参考にしてもらえますと幸いです:runner:。