Reduxの基本 ~ 公式ドキュメント Basics~

## はじめに
Reactを本格的に実装するためには，Reduxという代物を使うと良いらしいということを知り，実装したくてRedux調べてたけど一向に理解できない。。。
ということで，とりあえず[公式ドキュメント](https://redux.js.org/)を読み解くことにしました。

ちなみに，公式ドキュメントのBasicsの章のはじめにこうあります。
> Don't be fooled by all the fancy talk about reducers, middleware, store enhancers—Redux is incredibly simple. If you've ever built a Flux application, you will feel right at home. If you're new to Flux, it's easy too!

少なくとも今のところ，そうは感じられない。。。（能力不足）
ということで目標は以下。

## 目標
**ReduxドキュメントのBasicsを一通り理解する**
自分なりの解釈が間違ってるところとか出るかもしれないので悪しからず。。。

## Basics
ドキュメントのBasicsの章では，シンプルなToDoアプリを題材に，
1. Actions
2. Reducers
3. Store
4. Data Flow
5. Usage with React
6. Example: Todo List
の説明がされています。今回は1-5までをまとめようと思います。

### Actions
Actionとは，アプリからStoreに対して送るデータのこと。
新しいtodoの項目を追加するためのアクションは，

```js
const ADD_TODO = 'ADD_TODO'
```
```js
{
  type: ADD_TODO,
  text: 'Build my first Redux app'
}
```

という感じで書けます。ActionはJavaScriptの一般的なオブジェクトで，typeは必須プロパティ。
Actionの構造は好きにして定義して良いらしいです。ただ，Actionの中身（データ）はできるだけ小さい方が良くて，例えば，todoを完了するためのトグル用のActionは

```js
{
  type: TOGGLE_TODO,
  index: 5
}
```

こんな感じで，todoオブジェクト自体を入れるのではなくて， `index` だけを入れたりして小さくなるようにしたほうが良い。

todoリストの表示非表示を制御するためのactionは，

```js
{
  type: SET_VISIBILITY_FILTER,
  filter: SHOW_COMPLETED
}
```
こうなります。

#### Action Creators
Action Creatorとは，文字通りactionを生成する関数のこと。
ActionとAction Creatorは混同しやすいので気をつけましょう。

Action Creatorは次のようにActionを返すだけのシンプルな関数にします。

```js
function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}
```

ちなみに，Fluxでは次のようにAction Creator中でdispatchすることがよくあったらしい。

```javascript
function addTodoWithDispatch(text) {
  const action = {
    type: ADD_TODO,
    text
  }
  dispatch(action)
}
```

でも，Reduxではこんな書き方はせずに，`dispatch()`関数にActionの結果を渡すようにします。

```js
dispatch(addTodo(text))
dispatch(completeTodo(index))
```

これをラップしてBound Action Creatorを作ることもできます。

```js
const boundAddTodo = text => dispatch(addTodo(text))
const boundCompleteTodo = index => dispatch(completeTodo(index))
```

こうすると，

```js
boundAddTodo(text)
boundCompleteTodo(index)
```

こんな感じで直接dispatchすることができます。

`dispatch()`関数は`store.dispatch()`としてstoreから直接触ることもできるけど，react-reduxの`connect()`みたいなhelperを使ってアクセスするのが普通のようです。

[bindActionCreators()](https://redux.js.org/docs/api/bindActionCreators.html)を使って，自動的にAction creatorを`dispatch()`関数に接続することもできます。これは，Action Creatorが多くなったときに便利らしいですが，Advancedな用法ということなので，今回は割愛します。

### Reducers
Actionからは何が起きたのかという事実を知ることができます。ですが，アプリの状態(State)がどのように変化するのかということはわかりません。これを担うのが，Reducerです。

#### Stateの型を設計する
Reduxでは，全てのアプリの状態をひとつのオブジェクトとして保持します。この仕様のおかげで，コードを書く前に状態の持ち方を考えやすくなっているそう。

例えば，todoアプリの例だと，次の2種類の状態を保持したい。

- 表示/非表示のフィルタ
- todoリスト

UIの状態から保持するデータを決めがちですが，UIの状態とデータは出来るだけ分けて考えたほうが良いようです。

```js
{
  visibilityFilter: 'SHOW_ALL',
  todos: [
    {
      text: 'Consider using Redux',
      completed: true,
    },
    {
      text: 'Keep all state in a single tree',
      completed: false
    }
  ]
}
```

補足：
Stateはネストせず，出来るだけ正規化したほうが良いです。ストアする全てのオブジェクトはkeyとしてIDを持つようにして，他のエンティティからはできるだけIDを参照するようにします。アプリのstateはDBのように考えると良いようです。

#### Actionの操作
ここまでで，オブジェクトのStateが決まったので，Reducerを書きます。
Reducerは，前のStateとActionを持ち，次のStateを返す関数で，Actionの操作を司ります。

最初に，Reducerでしてはいけないことが記述されていました。

- 入力値の変更
- API呼び出しやルーティングの移行などの副作用を伴う操作
- ピュアじゃない関数の呼び出し（例：`Date.now()` や `Math.random()`）

要するに，**同じ入力が与えられたときに，次のStateを返すだけに留めるべきで，副作用が起きるようなAPIコールや，入力値の変更などはするべきではない**ということのようです。

Reduxは最初にStateを`undefined`としてReducerをコールします。このときに，Stateの初期化を行うようにします。

```js
import { VisibilityFilters } from './actions'

const initialState = {
  visibilityFilter: VisibilityFilters.SHOW_ALL,
  todos: []
}

function todoApp(state = initialState, action) {
  // アクションの操作はしない
  // 与えられたStateをただ返す
  return state
}
```

次に，`SET_VISIBILITY_FILTER`を操作してみます。ここでは`visibilityFilter`を変更するだけ。

```js
function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    default:
      return state
  }
}
```

ここで，

- `state`を変更していないこと
- デフォルト値として前のstateを返していること

に注意！`Object.assign()`のところは，オブジェクトの展開を使って`{ ...state, ...newState}`というようにも書くこともできます。

#### 複数のActionを操作する
複数Actionの操作の例は，

```js
import {
  ADD_TODO,
  TOGGLE_TODO,
  SET_VISIBILITY_FILTER,
  VisibilityFilters
} from './actions'

...

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    case ADD_TODO:
      return Object.assign({}, state, {
        todos: [
          ...state.todos,
          {
            text: action.text,
            completed: false
          }
        ]
      })
    default:
      return state
  }
}
```

となります。ここでは，`ADD_TODO`と`TOGGLE_TODO`をimportして， Reducerには`ADD_TODO`の操作を記述しています。

ここでも，`state`やそのフィールドを直接書かずに，代わりに新しいオブジェクトを返しています。この新しいオブジェクトは，古い`todos`オブジェクトに新しい`todos`を加えたオブジェクトになっています。
新しいtodoはActionのデータを使って，追加されていますね。

最後に，`TOGGLE_TODO`の操作の実装です。

```js
case TOGGLE_TODO:
  return Object.assign({}, state, {
    todos: state.todos.map((todo, index) => {
      if (index === action.index) {
        return Object.assign({}, todo, {
          completed: !todo.completed
        })
      }
      return todo
    })
  })
```

既存のActionを変更せずに，配列の特定の項目を更新したいので，該当するindexの項目以外の同じ項目の新しい配列を生成しています。
もし，この操作を頻繁に書くようであれば，immutablitiy-helper，updeepのようなヘルパーや，Immutableのようなライブラリを使うと良いよいです。この辺りはとりあえず割愛します。

また，クローンするまえに`state`の中身に何かを勝手に割り当てるとかそういうことはしてはいけません。あくまでクローンしたオブジェクトに関して変更を加えます。

#### Reducerの分割

まず，Reducerのコードの全容を。

```js
function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    case ADD_TODO:
      return Object.assign({}, state, {
        todos: [
          ...state.todos,
          {
            text: action.text,
            completed: false
          }
        ]
      })
    case TOGGLE_TODO:
      return Object.assign({}, state, {
        todos: state.todos.map((todo, index) => {
          if (index === action.index) {
            return Object.assign({}, todo, {
              completed: !todo.completed
            })
          }
          return todo
        })
      })
    default:
      return state
  }
}
```

`todos`や`visibilityFilter`は完全に独立して更新されています。
往々にして，Stateフィールドは他のフィールドに依存していたりして，考慮が必要だったりするようです。
ただ，今回の場合は簡単に`todos`を別関数に分割することができます。

```js
function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case TOGGLE_TODO:
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: !todo.completed
          })
        }
        return todo
      })
    default:
      return state
  }
}

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    case ADD_TODO:
      return Object.assign({}, state, {
        todos: todos(state.todos, action)
      })
    case TOGGLE_TODO:
      return Object.assign({}, state, {
        todos: todos(state.todos, action)
      })
    default:
      return state
  }
}
```

`todos`も`state`を受け取っていますが，これは配列であることに注意！
今，`todoApp`は`todos`にstateの一部分を渡し，`todos`がそれを更新します。
**これは，*reducer compositioin* と呼ばれ，Reduxアプリの基本的なパターン** のようです。

要は，共通するオブジェクトを返す部分は，それだけで抜き出して分割できるってことですね。

次に，`visibilityFilter`を管理するReducerの抜き出し方を見てみます。
まず， `SHOW_ALL`を宣言します。

```js
const { SHOW_ALL } = VisibilityFilters

function visibilityFilter(state = SHOW_ALL, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return action.filter
    default:
      return state
  }
}
```

メインのReducerを，Stateを部分的に管理するReducer達を呼んで，ひとつのオブジェクトで結びつける関数として書き換えることができます。
完全な初期状態を知る必要はもはやなく，子Reducerは最初，`undefined`を与えられたときの初期状態（`default`の返り値）を返せば良くなります。

```js
function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case TOGGLE_TODO:
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: !todo.completed
          })
        }
        return todo
      })
    default:
      return state
  }
}

function visibilityFilter(state = SHOW_ALL, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return action.filter
    default:
      return state
  }
}

function todoApp(state = {}, action) {
  return {
    visibilityFilter: visibilityFilter(state.visibilityFilter, action),
    todos: todos(state.todos, action)
  }
}
```

これらのReducerはグローバル状態の一部だけを管理していることに注意してください。各関数に渡される`state`はReducer毎に違います。

このようにすると，アプリが大きくなったときにReducerを別ファイルに分割し，各ファイルを完全に独立させて違うデータ領域を管理することができます。

Reduxは`combineReducers()`というユーティリティを提供していて，これは，上記のtodoAppと同じ定型ロジックを実行します。そのため，`todoApp`は`combineReducers()`を使って，書き直すことができます。

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

const todoApp = combineReducers({
  visibilityFilter,
  todos
})

export default todoApp
```

`combineReducers()`を使わずに，次のようにも書けます。

```js
export default function todoApp(state = {}, action) {
  return {
    visibilityFilter: visibilityFilter(state.visibilityFilter, action),
    todos: todos(state.todos, action)
  }
}
```

また，違うキーを使ったり，違う関数を呼ぶことも可能です。この2つのcombinedReducerの書き方は同じ動作をします。

```js
const reducer = combineReducers({
  a: doSomethingWithA,
  b: processB,
  c: c
})
function reducer(state = {}, action) {
  return {
    a: doSomethingWithA(state.a, action),
    b: processB(state.b, action),
    c: c(state.c, action)
  }
}
```

上の例の`combineReducers()`は全て，キーに対応して選択されたstateの一部を伴うReducerを読んで，その結果をひとつのオブジェクトに結合しています。
`combineReducers()`は，Reducerがstateを変更しない限り，新しいオブジェクトを生成しません。

個人的には，`combineReducers()`を使うほうが見やすいし理解しやすいと思います。他の方の記事を見ていても`combineReducers()`を使う例が多く，これを使うのが自然な気がしています。

### Store
ここまでで，

- 何が起きるのかついての事実を表現するAction
- Actionに応じてstateを更新するReducer

を定義しました。

Storeは上記2つをつなげるオブジェクトになります。Storeは以下のような役割を担っています。

- アプリのstateを保持する
- `getState()`でstateへのアクセスを許可する
- `dispatch()`でstateを更新することを許可する
- `subscribe(listener)`でリスナーを登録する
- `subscribe(listener)`で返される関数を通して，リスナーの登録解除を行なう

**Reduxアプリ内ではただひとつのStoreを持つ**ということは重要な注意事項なので忘れないようにしましょう！

データ操作のロジックを分割したいときには，Storeをたくさん使う代わりに，reducer compositionを使って分割します。

Reducerを既に準備していたら，storeを作るのは簡単です。
`combineReducers()`でまとめたReducerをimportして，`createStore()`に渡すだけです。

```js
import { createStore } from 'redux'
import todoApp from './reducers'

let store = createStore(todoApp)
```

第2引数で初期状態を設定することも可能です。
これはサーバ上で実行しているReduxアプリのstateとクライアントのstateを一致させるのに役立ったりするようです。

```js
let store = createStore(todoApp, window.STATE_FROM_SERVER)
```
とりあえずこういうのもあるよ。ということですね。必要になったら再度調べよう。。。

#### Actionをdispatchする
Storeを生成したら，プログラムが動くことを確認してみましょう。実行の仕方は以下のようにします。UIがなくても，更新ロジックをテストすることができます。

```js
import {
  addTodo,
  toggleTodo,
  setVisibilityFilter,
  VisibilityFilters
} from './actions'

// Log the initial state
console.log(store.getState())

// Every time the state changes, log it
// Note that subscribe() returns a function for unregistering the listener
const unsubscribe = store.subscribe(() =>
  console.log(store.getState())
)

// Dispatch some actions
store.dispatch(addTodo('Learn about actions'))
store.dispatch(addTodo('Learn about reducers'))
store.dispatch(addTodo('Learn about store'))
store.dispatch(toggleTodo(0))
store.dispatch(toggleTodo(1))
store.dispatch(setVisibilityFilter(VisibilityFilters.SHOW_COMPLETED))

// Stop listening to state updates
unsubscribe()
```

Reduxを使うと，全てがピュアな関数で表現されることになるので，UIを書くことなくアプリの挙動を確認できます。だから，テストも書きやすいんですね。ただ関数をコールして，アウトプットを確認するだけ。いいですね。

### Data Flow
Reduxアーキテクチャは、単一方向の厳密なデータフローを中心に展開されます。
どういうことかというと，アプリ内のデータは全て，同じライフサイクルのパターンに従うので，アプリのロジックはより理解しやすいものになります。予想外のことをしたりすることはできないので，結果的にわかりやすくなるはずであるということのようです。
また，こうすることで，データの正規化が促進され，相互に認識されない同一データのコピーが作成されることはなくなります。

つまりは，単一方向のデータフローにすることで，データフローを追いやすく，不要なデータのコピーとかが作成されにくくなっているようです。

Reduxアプリのデータライフサイクルは以下の4つのステップに従います。

**1. `store.dispatch(action)`を呼ぶ**
Actionは何が起こったのか，だけを説明する一般的なオブジェクトです。Storeに対するdispatch()はアプリ内のどこからでも呼び出し可能になります。

```js
 { type: 'LIKE_ARTICLE', articleId: 42 }
 { type: 'FETCH_USER_SUCCESS', response: { id: 3, name: 'Mary' } }
 { type: 'ADD_TODO', text: 'Read the Redux docs.'
```

**2. Reduxのstoreは，reducer関数を呼ぶ**
Storeは，現在のStateツリーとActionの2つをReducerに渡します。例えば，todoアプリにおいて，Root reducerは次のようになります。

```js
// The current application state (list of todos and chosen filter)
let previousState = {
  visibleTodoFilter: 'SHOW_ALL',
  todos: [
    {
      text: 'Read the docs.',
      complete: false
    }
  ]
}

// The action being performed (adding a todo)
let action = {
  type: 'ADD_TODO',
  text: 'Understand the flow.'
}

// Your reducer returns the next application state
let nextState = todoApp(previousState, action)
```

Reducerはピュアな関数であることに注意してください！Reducerはただ次のStateを計算しているだけです。Reducerに対して，同じ入力をすると，いくらやっても同じ出力しか出てきません。
APIコールやルーターの遷移のような副作用を起こすことはありません。ただ，次のStateを返すだけです。APIコールのような操作は，アクションがdispatchされる前に行われるべき操作です。

***3. Root reducerは，複数のreducerの出力をひとつのStateツリーに結合する***
どのようにRoot reducerを構成するかは自由に決めて良いようです。
Reduxはreducerを分割して管理するための`combineReducers()`というヘルパー関数を持っているので，これを使うことが推奨されています。書き方は以下のようになります。

```js
function todos(state = [], action) {
   // Somehow calculate it...
   return nextState
 }

 function visibleTodoFilter(state = 'SHOW_ALL', action) {
   // Somehow calculate it...
   return nextState
 }

 let todoApp = combineReducers({
   todos,
   visibleTodoFilter
 })
```

Actionを実行するとき，`combineReducers()`によって返ってきた`todoApp`は両方のreducer呼びます。

```js
 let nextTodos = todos(state.todos, action)
 let nextVisibleTodoFilter = visibleTodoFilter(state.visibleTodoFilter, action)
```

これは2つの結果をひとつのstateツリーに結合します。

```js
 return {
   todos: nextTodos,
   visibleTodoFilter: nextVisibleTodoFilter
 }
```

どうやら，関数の名前がオブジェクトのkeyになっているようですね。

**4. ReduxのStoreは，Root reducerから返ってきた完全なStateツリーを保存する**
新しいツリーはアプリの次のStateになります。このとき，`store.subscribe(listener)`で登録された全てのリスナーが呼び出されることになります。リスナーが，現在のstateを取得するときには`store.getState()`を呼んで取得します。

このタイミングで，新しいStateを反映するためにUIが更新されます。React Reduxのようなバインディングを使用しているときは，component.setState(newState)が呼ばれ，更新されることになります。

### Reactとの併用方法
ReduxはReactに依存しているわけではないため，Angular，Ember，jQuery，vanilla JavaScriptなどで使用することができます。ただ，ReactとDekuはstateの関数としてUIを記述できるためReduxと相性が良いといえます。ReduxはActionに応じてStateの更新を行います。

#### react-reduxのインストール
react-reduxを使用するためnpmでインストールします。npmを使わない方法もありますが割愛します。

```bash
$ npm install --save react-redux
```

#### Presentational and Container Components
Reduxを使用したReactには，

- Presentational components
- Container components

の2つのコンポーネントがあります。

Container Componentsが，Reduxを使ったコンポーネントになります。
ほとんどのコンポーネントはPresentationalになります。一般的なReactのコンポーネントと思ってもらって良いです。ReduxのstoreをPresentational Componentsに紐付けるためにContainer Componentsを生成する必要があります。
もし，Container Componentsが複雑になりすぎる（例えば，Presentional Componentsがたくさんネストしていて，下位に渡されるコールバックが大量にある）場合，コンポーネントツリー内のもう一つのコンテナを導入した方が良いです。

`store.subscribe()`を使えば手でContainer Componentsを書くこともできますが，React Reduxは手で書いて最適化するのは難しいみたいなので辞めておいた方が良さそうです。
`connect()`関数を使ってContainer Componentsを生成することが推奨されています。

#### コンポーネントの階層を設計する
コチラに関してはドキュメントでも他記事参照となっていたので割愛します。
(Thinking in React)[https://reactjs.org/docs/thinking-in-react.html]を参照。

#### Presentational Componentsを設計する
Presentational Componentsと，その中身の説明を簡単に列挙すると下のようになります。

- `TodoList` は表示するtodosのリスト
    - `todos: Array` はtodoの項目の配列 `{id, text, completed}`
    - `onTodoClick(id: number)` はtodoをクリックしたときに発火するコールバック
- `Todo` はtodoの項目
    - `text: string`はテキスト
    - `completed: boolean`は表示するかどうか
    - `onClick()`はtodoがクリックされたときに発火するコールバック
- `Link`はコールバックを伴うリンク
    - `onClick()`はクリックされたときに発火するコールバック
- `Footer`は表示されているtodosをユーザに変更させる場所
- `App`はルートコンポーネント

これらは，*見た目*を描画しますが，どこからデータが来るのかや，どうやってデータを変更するかは知りません。ただ与えられたものをレンダーするだけです。
あるものがReduxから渡されたとき，コンポーネントは常に同じものになります。

#### Container Componentsの設計
Container Componentsは，Presentational ComponentsをReduxに接続するために必須です。
例えば，Presentationalな`TodoList`コンポーネントは，ReduxのStoreを定期的にみて，現在のvisibility filterを適用する`VisibleTodoList`のようなコンテナを必要とします。また，visibility filterを変更するために，適切なクリックアクションをdispatchする`Link`をレンダーする`FilterLink`コンテナコンポーネントも必要です。
まとめると，

- `VisbleTodoList`は現在のvisibility filterに応じてtodosを絞り込み，`TodoList`を描画する
- `FilterLink`は現在のvisibility filterを取得し，`Link`を描画する
    - `filter: string`は表示するvisibility filter

#### 他のコンポーネントを設計する
コンポーネントを必ず，Presentationalか，Containerかに区別しなければならなないわけではありません。例えば，コンポーネントが小さく，formと関数が一緒になっている場合などがあります。

- `AddTodo`はAddボタンを伴うinputフィールド

技術的に分割することはできるけど，分割するほどじゃない場合は，両者を一緒に書いてしまったほうがよいかもしれません。これが大きくなってくると，どのように分ければいいかが自ずと見えてくるようです。

#### Presentational Componentsの実装
これは普通のReactコンポーネントなので，Reduxのドキュメントでは詳細には触れられていませんでした。それぞれのコンポーネントを下に貼っておきます。単純なReactのコンポーネントです。

```js:components/Todo.js
import React from 'react'
import PropTypes from 'prop-types'

const Todo = ({ onClick, completed, text }) => (
  <li
    onClick={onClick}
    style={ {
      textDecoration: completed ? 'line-through' : 'none'
    }}
  >
    {text}
  </li>
)

Todo.propTypes = {
  onClick: PropTypes.func.isRequired,
  completed: PropTypes.bool.isRequired,
  text: PropTypes.string.isRequired
}

export default Todo
```

```components/TodoList.js
import React from 'react'
import PropTypes from 'prop-types'
import Todo from './Todo'

const TodoList = ({ todos, onTodoClick }) => (
  <ul>
    {todos.map((todo, index) => (
      <Todo key={index} {...todo} onClick={() => onTodoClick(index)} />
    ))}
  </ul>
)

TodoList.propTypes = {
  todos: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.number.isRequired,
      completed: PropTypes.bool.isRequired,
      text: PropTypes.string.isRequired
    }).isRequired
  ).isRequired,
  onTodoClick: PropTypes.func.isRequired
}

export default TodoList
```

```components/Link.js
import React from 'react'
import PropTypes from 'prop-types'

const Link = ({ active, children, onClick }) => {
  if (active) {
    return <span>{children}</span>
  }

  return (
    <a
      href=""
      onClick={e => {
        e.preventDefault()
        onClick()
      }}
    >
      {children}
    </a>
  )
}

Link.propTypes = {
  active: PropTypes.bool.isRequired,
  children: PropTypes.node.isRequired,
  onClick: PropTypes.func.isRequired
}

export default Link
```

```components/Footer.js
import React from 'react'
import FilterLink from '../containers/FilterLink'

const Footer = () => (
  <p>
    Show:
    {' '}
    <FilterLink filter="SHOW_ALL">
      All
    </FilterLink>
    {', '}
    <FilterLink filter="SHOW_ACTIVE">
      Active
    </FilterLink>
    {', '}
    <FilterLink filter="SHOW_COMPLETED">
      Completed
    </FilterLink>
  </p>
)

export default Footer
```

#### Container Componentsの実装
技術的には，Container Componentsは，ReduxのStateツリーの一部分を読んだり，描画するPresentational Componentsのプロパティを供給するためのReactコンポーネントである。Container Componentsの中で，`store.subscribe()`を使ってPresentational ComponentsとReduxを接続することになる。
だが，Container ComponentsはReact Redux ライブラリの`connect()`関数を使うことが推奨されている。これを使うことによって，Reactのレンダリングが最適化されようです。

`connect()`を使うためには，現在のReduxのStoreのStateを，Presentational Componentsに渡すプロパティ場合に変換する必要がある。この方法を示しているのが，`mapStateToProps`という関数で，これを定義しないといけないようです。
例えば，`VisibleTodoList`は`TodoList`に渡すための`todos`を計算する必要があるので，`state.visibilityFilter`に対応する`state.todos`を絞り込む関数を定義します。そして，`mapStateToProps`でそれを使用する。

```js
const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'SHOW_COMPLETED':
      return todos.filter(t => t.completed)
    case 'SHOW_ACTIVE':
      return todos.filter(t => !t.completed)
    case 'SHOW_ALL':
    default:
      return todos
  }
}

const mapStateToProps = state => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}
```

さらにStateを読むことに加えて，Container ComponentsはActionをdispatchすることができます。dispatch()メソッドを受け取って，Presentational Componentsに挿入したいpropsのコールバックを返す`mapDispatchToProps()`という関数を定義することができます。

例えば`TodoList`コンポーネントに`onTodoClick`というプロパティを挿入するためには，`VisibleTodoList`と，`TOGGLE_TODO`アクションをdispatchする`onTodoClick`が必要になります。

```js
const mapDispatchToProps = dispatch => {
  return {
    onTodoClick: id => {
      dispatch(toggleTodo(id))
    }
  }
}
```

最後に，`connect()`を呼び，これらの2つの関数を渡す`VisibleTodoList`を生成します。

```js
import { connect } from 'react-redux'

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

export default VisibleTodoList
```

これらは，React redux APIの基本ですが，もっと簡単に記述する方法があるので，気になる方は[ドキュメント](https://github.com/reactjs/react-redux)を参照。
残りのコンテナコンポーネントの書き方は以下のようになります。

```containers/FilterLink.js
import { connect } from 'react-redux'
import { setVisibilityFilter } from '../actions'
import Link from '../components/Link'

const mapStateToProps = (state, ownProps) => {
  return {
    active: ownProps.filter === state.visibilityFilter
  }
}

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    onClick: () => {
      dispatch(setVisibilityFilter(ownProps.filter))
    }
  }
}

const FilterLink = connect(
  mapStateToProps,
  mapDispatchToProps
)(Link)

export default FilterLink
```

```containers/VisibileTodoList.js
import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'SHOW_ALL':
      return todos
    case 'SHOW_COMPLETED':
      return todos.filter(t => t.completed)
    case 'SHOW_ACTIVE':
      return todos.filter(t => !t.completed)
  }
}

const mapStateToProps = state => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

const mapDispatchToProps = dispatch => {
  return {
    onTodoClick: id => {
      dispatch(toggleTodo(id))
    }
  }
}

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

export default VisibleTodoList
```

#### 他のコンポーネントの実装

```containers/AddTodo.js
import React from 'react'
import { connect } from 'react-redux'
import { addTodo } from '../actions'

let AddTodo = ({ dispatch }) => {
  let input

  return (
    <div>
      <form
        onSubmit={e => {
          e.preventDefault()
          if (!input.value.trim()) {
            return
          }
          dispatch(addTodo(input.value))
          input.value = ''
        }}
      >
        <input
          ref={node => {
            input = node
          }}
        />
        <button type="submit">
          Add Todo
        </button>
      </form>
    </div>
  )
}
AddTodo = connect()(AddTodo)

export default AddTodo
```

refとかよく分かってないけど今回は飛ばします。こう書けばいいらしいということはわかる。


#### コンポーネント内でコンテナを結びつける

```js:components/App.js
import React from 'react'
import Footer from './Footer'
import AddTodo from '../containers/AddTodo'
import VisibleTodoList from '../containers/VisibleTodoList'

const App = () => (
  <div>
    <AddTodo />
    <VisibleTodoList />
    <Footer />
  </div>
)

export default App
```

#### Storeの渡し方
Container Componentsは，ReduxのStoreにアクセスする必要があるので，Storeにsubscribeすることができる。全てのコンテナコンポーネントにpropとして渡す方法もありますが，それは何かと面倒らしいです。Presentational Componentsのコールバックのネストが深くなったりしたときにいちいち手で書かないといけなかったりするらしい。

それを解決するために，`<Provider>`を使用して接続することが推奨されているようです。

```js:index.js
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'
import App from './components/App'

let store = createStore(todoApp)

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)
```

## まとめ
以上で，Basicsの記述は一通り読むことができました。
Container Componentsを書いて，ReactのPresentational Componentsに対してStoreの情報を渡せるんですね。このあたりは実装しながら理解を深められたらと思います。

## 参考文献
[Redux公式ドキュメント](https://redux.js.org/docs/basics/)