たぶんこれが一番分かりやすいと思います React + Redux のフロー図解

【追記】

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">もうこれ古いから参考にしないでください <a href="https://t.co/mXtcc73Orf">https://t.co/mXtcc73Orf</a></p>&mdash; もし Laravel が流行しなくなってこられてきてたとしたら、絶対に捨てられてこられてたと思うか (@mpyw) <a href="https://twitter.com/mpyw/status/1354019510412435456?ref_src=twsrc%5Etfw">January 26, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Redux にはその昔 connect()() とかいうクソ API と， Redux-Saga とかいう宗教がありました<br><br>という考古学です</p>&mdash; もし Laravel が流行しなくなってこられてきてたとしたら、絶対に捨てられてこられてたと思うか (@mpyw) <a href="https://twitter.com/mpyw/status/1354019694777274371?ref_src=twsrc%5Etfw">January 26, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

-------

# 読者対象

- [Tutorial: Intro To React - React](https://facebook.github.io/react/tutorial/tutorial.html)
- [Example: Todo List · Redux](http://redux.js.org/docs/basics/ExampleTodoList.html)

「チュートリアルそれぞれ一周した！Reactは何とか理解できたが，**Reduxがさっぱりわかんねぇ！**」

ぐらいの人向け。自分もまだ未熟なので理解の確認のために書いた。

# 「React」と「React+Redux」の決定的な違い

- React単体の場合，Reactコンポーネント自身が個別に状態管理をする。
- React+Reduxの場合，**状態管理する専用の場所(ストア)**で状態管理し，Reactコンポーネントはそれを映すだけに徹する。

# Redux図解

## フロー全体図

![ReactRedux-DataFlow.svg.png](https://qiita-image-store.s3.amazonaws.com/0/25060/53796a37-edac-aee1-02ae-e59bde9cc917.png)

## Store

状態は基本的に全てここで集中管理される。イメージとしては**「でっかいJSONの塊」**。

```js:例&#58;&#32;カウンタ
{
    value: 0,
}
```

規模が大きい場合は状態をカテゴリ別に分類するのが一般的である。

```js:例&#58;&#32;TwitterがもしReduxを使っていたら
{
    // セッションに関するもの
    session: {
        loggedIn: true,
        user: {
            id: "114514",
            screenName: "@mpyw",
        },
    },

    // 表示中のタイムラインに関するもの
    timeline: {
        type: "home",
        statuses: [
            {id: 1, screenName: "@mpyw", text: "hello"},
            {id: 2, screenName: "@mpyw", text: "bye"},
        ],
    },

    // 通知に関するもの
    notification: [],
}
```

## Action および Action Creator

Storeおよびそこに存在するStateはとても神聖なものだ。Reactコンポーネントなんぞ下界のものに直接触らせるわけにはいかんのだ。ここに触れるためには，Actionという儀式を介さなければならない。要するに**イベント・ドリブン**と同じ概念だ。

1. Storeに対して何かしたい奴はActionを発行する
2. Storeの門番がActionの発生を検知すると，Stateが更新される

Actionは基本的に以下のようなフォーマットを持つオブジェクトになる。

```js
{
    type: "アクションの種類を一意に識別できる文字列またはシンボル",
    payload: "アクションの実行に必要な任意のデータ",
}
```

例えば，カウンタの値を2増加させたい場合，以下のようなオブジェクトになるだろう。頭に `@@myapp/` とプレフィックスをつけたのは，他の人が書いたコードとの衝突を避けるためだ。

```js
{
    type: "@@myapp/ADD_VALUE",
    payload: 2,
}
```

ところで，いちいちこんなオブジェクトを作るのを手作業で書かせるのもつらい。また，`"@@myapp/ADD_VALUE"`のように毎回アクション名を文字列で書くのも嫌な感じがする。そこで，これを少し楽にするための定数と関数を用意するのが一般的である。外部ファイルから参照する必要性に備えて，ちゃんとexportもしておこう。

![ReactRedux-Action.svg.png](https://qiita-image-store.s3.amazonaws.com/0/25060/a95be793-4eb1-49f0-0b90-9a30e3e92625.png)

```js:actions.js
export const ADD_VALUE = '@@myapp/ADD_VALUE';
export const addValue = amount => ({type: ADD_VALUE, payload: amount});
```

## Reducer

先ほど「Storeの門番」と書いたが，それに相当する役目を背負っているのがこいつだ。

関数型プログラミングにおいて，Reduceという用語は畳み込み演算を意味する。Reduxにおいては，以下のように，**以前の状態とアクションを組み合わせて，新しい状態を生み出す**という操作になる。

![ReactRedux-Reducer.svg.png](https://qiita-image-store.s3.amazonaws.com/0/25060/7bfa7488-834d-b022-4307-766ad9a63e4f.png)

```js:reducer.js
import { ADD_VALUE } from './actions';

export default (state = {value: 0}, action) => {
    switch (action.type) {
        case ADD_VALUE:
            return { ...state, value: state.value + action.payload };
        default:
            return state;
    }
}
```

***※ 2018年4月現在 [Object rest spread transform](http://babeljs.io/docs/plugins/transform-object-rest-spread) 必須の記法が含まれています。このコードを使用される場合は各自プラグインをインストールしてください。***

注意して見るべきは以下の2点。

- **初期状態はReducerのデフォルト引数で定義される**
- 状態を変更する際，渡されてきた`state`そのものを書き換えずに，新しいものを合成するように書く

さて，こいつがリターンした`state`は，ストアにすぐ反映され，以下のように変化する。

```js
{
    value: 2,
}
```

Twitterの例のように，大規模な開発においてReducerを細かく分割する場合は，Reduxによって提供される`combineReducers`という関数を用いて，以下のように書く。

```js
import { combineReducers } from 'redux';

const sessionReducer = (state = {loggedIn: false, user: null}, action) => {
    /* 省略 */
};
const timelineReducer = (state = {type: "home", statuses: []}, action) => {
    /* 省略 */
};
const notificationReducer = (state = [], action) => {
    /* 省略 */
};

export default combineReducers({
    session: sessionReducer,
    timeline: timelineReducer,
    notification: notificationReducer,
})
```

こうすると，**Reducer分割に使われたキーがそのままState分割にも流用される**。なお実際には，それぞれのReducerの定義自体も別ファイルに分けるのが普通だ。

## 純粋なComponentと接続されたComponent

ReactのComponent単体では，Reduxの流れに乗ることはできない。参加するためには，ReactReduxによって提供される`connect`という関数を用いて，以下のように書く。関数版とクラス版それぞれを示す。

![ReactRedux-Component.svg.png](https://qiita-image-store.s3.amazonaws.com/0/25060/a2ab35eb-acf5-be06-b5ca-043aa54a0f98.png)

```jsx:Counter.js&#32;(関数版)
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { addValue } from './actions';

const Counter = ({ value, dispatchAddValue }) => (
    <div>
        Value: {value}
        <a href="#" onClick={e => dispatchAddValue(1)}>+1</a>
        <a href="#" onClick={e => dispatchAddValue(2)}>+2</a>
    </div>
);

export default connect(
    state => ({ value: state.value }),
    dispatch => ({ dispatchAddValue: amount => dispatch(addValue(amount)) })
)(Counter)
```

```jsx:Counter.js&#32;(クラス版)
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { addValue } from './actions';

class Counter extends Component {
    render() {
        const { value, dispatchAddValue } = this.props;
        return (
            <div>
                Value: {value}
                <a href="#" onClick={e => dispatchAddValue(1)}>+1</a>
                <a href="#" onClick={e => dispatchAddValue(2)}>+2</a>
            </div>
        );
    }
}

export default connect(
    state => ({ value: state.value }),
    dispatch => ({ dispatchAddValue: amount => dispatch(addValue(amount)) })
)(Counter)
```

さあ，ここで途端に図式が複雑になる気がする。自分がReduxを勉強している最中に，最も理解に時間がかかった部分がここだ。分かってしまえば大したことないので，焦らず冷静に見ていこう。

まず，ComponentがStoreから何か情報を受け取る場合，それは`props`を通じて渡されてくる。`props`はイミュータブルだ。状態が更新されるたびに新しく`props`が作り直され，その都度`render`メソッドが実行される。これを踏まえた上で，`connect`を実行している周囲のコードを見てみよう。

1. Store が持つ状態`state`をどのように`props`に混ぜ込むかを決める<br>**（この動作を定義する関数は`mapStateToProps`と呼ばれる）**
2. Reducer にアクションを通知する関数`dispatch`をどのように`props`に混ぜ込むかを決める<br>**(この動作を定義する関数は`mapDispatchToProps`と呼ばれる)**
3. 上記2点が混ぜ込まれた`props`を受け取りたい Component を決める
4. Store や Reducer と繋がれるように細工された Component が返り値になる

`connect(mapStateToProps, mapDispatchToProps)(Component)` という書き方には独特の雰囲気があるが，最終的な返り値は4のようなものである。以下では，`mapStateToProps`と`mapDispatchToProps`についてさらに解説する。

### mapStateToProps

引数として渡されてくる`state`は**全体を意味する**ことに注意されたい。カウンタの例では

```js
{
    value: 2,
}
```

が

```html
<Counter value={2} />
```

と入ることを期待して `state => ({ value: state.value })` と書いた。今回の場合は他に邪魔なプロパティが一切存在しないので `state => state` と書いても動作するが，基本的に**必要なものだけを選別して`props`に混ぜ込む**のが普通だ，ということを覚えておこう。

### mapDispatchToProps

Action Creator でアクションを作っても，それだけでは何も起こらない。Reducerに向けて通知するには，作ったアクションを，ここで渡されてくる`dispatch`という関数にさらに渡さなければならない。

こうすると，**すべてのReducerが実行される**。Reducer にswitch文での分岐が書かれていたのはこのためである。Reducer は，関係無いアクションは無視して，自分宛てのアクションだけを処理するように書かなければならない。

また，**コンポーネント側でいちいち手動で`dispatch`する処理を書かなくて良いように，ここでアクションの生成から`dispatch`の実行までを一気に行う関数を定義して`props`に渡してあげよう**，というのがこいつの主な存在意義である。

### bindActionCreators

なんと，`mapDispatchToProps`で上記のようなコードを書くことさえサボることのできる，`bindActionCreators`という関数も提供されている。これを使えば以下のような省略が可能だ。

![ReactRedux-BoundActionCreator.svg.png](https://qiita-image-store.s3.amazonaws.com/0/25060/344d8656-b70d-f206-a670-e869b5b2ca3b.png)

```jsx
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { addValue } from './actions';


const Counter = ({ value, addValue }) => (
    <div>
        Value: {value}
        <a href="#" onClick={e => addValue(1)}>+1</a>
        <a href="#" onClick={e => addValue(2)}>+2</a>
    </div>
);

export default connect(
    state => ({ value: state.value }),
    dispatch => bindActionCreators({ addValue }, dispatch)
)(Counter)
```

**2017/06/25 追記:** 現在は`bindActionCreators`の実行も省略することができる。

```jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { addValue } from './actions';


const Counter = ({ value, addValue }) => (
    <div>
        Value: {value}
        <a href="#" onClick={e => addValue(1)}>+1</a>
        <a href="#" onClick={e => addValue(2)}>+2</a>
    </div>
);

export default connect(
    state => ({ value: state.value }),
    { addValue }
)(Counter)
```

### Container

今回は単に「接続されたComponent」と呼んだが，場合によっては「Container」と呼ばれるべきComponentも出てくる。以下のようなものが該当する。

- たくさんのComponentがリスト形式で集められているが，各要素のComponent各々で接続すると収拾がつかなくなるので，代表して子要素を抱えるだけの1つの親Componentがconnectされにいく

```jsx:このような状況
(<UsersList>
    <User />
    <User />
    <User />
    <User />
</UsersList>)
```

この**代表してconnectされにいく親Component**のことを**Container**と呼ぶ。Containerは可読性を高めるために，Componentとはディレクトリが分けられることが多い。


## 理解度チェック

ここまで一通り理解すれば，あとは画像を見返すだけで大まかに「Reduxがどんな動きをするか」は思い出せると思う。

![ReactRedux-DataFlow.svg.png](https://qiita-image-store.s3.amazonaws.com/0/25060/53796a37-edac-aee1-02ae-e59bde9cc917.png)

# 発展

## Redux Saga の導入

実はReact+Reduxだけでは，まだ困ることがある。

- **Reducerの中には副作用を生む処理を書いてはいけない**

という原則があるからだ。

- 同じ入力に対して確率的に結果が変化する処理
- 遅延処理
- HTTPリクエスト処理

こういったものは基本的にReducerの中には書いてはいけない。ではいったいどこに書くべきなのか？

- Component の中
- Action Creator の中
- `mapDispatchToProps` の中

いやいや，これらは全部アンチパターンだ。正しい答えは **Saga** だ。

![ReactRedux-DataFlow-with-Saga.svg.png](https://qiita-image-store.s3.amazonaws.com/0/25060/d0327edb-22d5-f2de-d436-82cfa0083730.png)

今までは， connectされたComponentからアクションが`dispatch`されると，それはReducerに向かうだけ，と決まっていた。ここに新しい受け手を用意するのが Saga である。

**Sagaは全てジェネレータ関数であるため，非同期処理を簡単に捌くことができる。**

1. **`yield take(ACTION_TYPE)` で指定したアクションの発生を監視する**
2. 取ってきたアクションで煮るなり焼くなりする
3. **`yield put(action)` で結果をまた別のアクションとして排出する**

基本はこれだけだ。排出したアクションはReducerに向かうこともあるし，自分自身のSagaにもう一度流入してくるかもしれないし，自分以外の別のSagaに流入していくかもしれない。

[redux-sagaで非同期処理と戦う - Qiita](http://qiita.com/kuy/items/716affc808ebb3e1e8ac)

上の記事が非常に秀逸なので，Sagaについて詳しく知りたい方は是非とも一読を。