ReactのプロジェクトにReduxを導入する。

# 利用プロジェクト
**[React-Todo](https://github.com/gcmae/react-todo)**
# Flux
Reactだけだと、データが大規模になりソースが肥大化してしまう欠点があります。
それらを解消するため、Facebookが編み出したデザインパターンをFluxと言います。

今回はそのFluxフレームワークの一つである**Redux**を主軸に
規模が大きくなりデータの管理が難しくなったReactのプロジェクトに
Reduxを導入するところを記載します。

# Reduxデータフロー
## Action(アクション)
Viewから呼ばれるStateに関する関数群
それぞれ、該当するReducerを呼ぶ。
## Reducer(レジューサ)
Actionを受け取り、それに従って書き換えるStateの中身を作る。
ここでは、Stateは書き換えない。
## Dispatch(ディスパッチ)
Actionを呼ぶ際に利用され、Dispatchを通すことでStateの更新が可能になります。
## Store(ストア)
ActionとReducerを結びつける。dispatchを通してReducerから受け取ったStateのコピーの内容でStateを書き換える。
## Container(コンテナ)
Storeが持つStateをReactのプロパティとしてViewと結びつける役割を持つ。
## View(ビュー)
Reactのコンポーネントの部分、Stateを表示する。

# Reduxの導入手順
## 1. ライブラリをインストールする。
必要なものは、以下の２点です。
1. Redux
Redux本体
2. React-Redux
ReactとReduxを結びつけるライブラリ

コマンドでインストールします。

```bash
# Redux
# npm
npm install redux
# yarn
yarn add redux

# React-Redux
# npm
npm install react-redux
# yarn
yarn add react-redux

```

## 2. ReactとReduxを結びつける。
まず、最初の手順としてReactとReduxを結びつけます。
記述するのはindex.jsxです。

``` index.js
// ./index.jsx
import React from 'react'
import ReactDOM from 'react-Fdom'
// ①
import { createStore } from 'redux'
import { Provider } from 'react-redux'

// ② 4の項目で解説
import App from './containers/App'

// ③ 次の項目で解説
import reducer from './reducers/reducer'

// ④
const store = createStore(reducer)

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

①. ReduxのcreateStore, React-ReduxのProviderをインポートします。
②. 4の項目で解説しますが、作成したAppのContainerをインポートします。
③. 次の項目で解説しますが、作成したReducerをインポートします。
④. reducerを元に、ReduxのcreateStoreでStoreを作成します。
⑤. ProviderにstoreをPropsとして渡し,App(Component)とStoreを結びつけます。

## 3. Reducerを作成する。
次に、書き換えるStateの中身を作成するReducerを作成します。

``` reducer.js
// ./reducers/reducer.jsx
// 初期State
const initialState = {
  tasks: [],
  text: '',
}
// Reducer処理
const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADDTASK': {
      return console.log(action.value)
    }
    case 'ENDTASK': {
      return console.log(action.value)
    }
    case 'UPDTASK': {
      return console.log(action.value)
    }
    case 'DELTASK': {
      return console.log(action.value)
    }
    default: {
      return state
    }
  }
}

export default reducer

```

Reducerの最初はStateの初期値です。
今回のReact-Todoでは、
1. ADD: Todoの追加
2. END: Todoの完了
3. UPD: Todoの更新
4. DEL: Todoの削除
以上、４つのState変更があります。
ReducerはActionから「ActionType」というものを引数で受け取り、その中身でSwitchケースの中の該当する処理を行います。
今はまだ処理を書かず、return nullとしていますが、
例えば**ADDTASK**では、**現状のStateの追加するTodoを追加**する処理を記述します。
(なんとも説明が下手なのですが....)
ざっくりいうと、**State自体は書き換えずにStateを更新した際の値をreturn**する処理を記述します。
この項で作成したreducerを前の項のreducerとしてimportしましょう。

## 4. Containerを作成する。
ReduxのStoreが持つStateをReactのコンポーネントが利用できるようにするため、Containerを作成します。

``` app.js
// ./containers/App.jsx
import {
  connect,
} from 'react-redux'

import App from './../components/App'

const mapStateToProps = (state) => {
  return state
}

export default connect(mapStateToProps)(App)

```

React-Reduxは、connectというプロパティを持っています。
mapStateToPropsは、全体的なStateの中から利用するStateを持ってきてくれる関数です。
正直、中でどう動いているのか、どういう意味なのかははっきりは僕もわかりません。
なので、**これはお作法だ**、と考えています。

最後の行、connectを利用して、mapStateToPropsが取ってきたStateの値をAppで利用できるように繋げています。

containerに関しては、ほとんどこれだけです。
大規模になればなるほど、mapStateToPropsで利用するStateが多くなります。

## 5. Actionを作成する。
Actionsには、Reducerへ渡すActionTypeとStateへ追加、または更新する値を渡します。

``` AppActions.js
// ./actions/AppActions.jsx
const Actions = {
  addTodo(value) {
    return {
      type: 'ADDTASK',
      value,
    }
  },
  fixTodo(value) {
    return {
      type: 'FIXTASK',
      value,
    }
  },
  updTodo(value) {
    return {
      type: 'UPDTASK',
      value,
    }
  },
  delTodo(value) {
    return {
      type: 'DELTASK',
      value,
    }
  },
}

export default Actions

```

各関数の中でreturnすることで、Reducerへ引数が渡されます。(returnの値)
それぞれReducerの中で**action.type** , **action.value**で取得できます。

addTodoであれば、typeがADDTASKなので
Reducer内の**ADDTASK**の処理を行います。

valueは、Componentから渡される値です。

Actionに記載している関数一つ一つを**ActionCreator**と呼びます。


# Reduxのデータフロー
以上でReduxの導入で必要なファイル群の作成は完了しました。
続いて実際に、Actionを読んで、Reducerが値を作成し、StoreがStateを書き換えるという流れを記載、もとい現状の処理をReduxへ書き換える処理を記述していきます。

## 1. ActionCreatorを呼ぶ
ReactのViewからReducerを呼ぶにはdispatchが必要です。
そのため、Containerに以下の記述を行います。

``` App.js
// ./containers/App.jsx
import {
  connect,
} from 'react-redux'

import App from './../components/App'
import Actions from './../actions/AppActions'

const mapStateToProps = (state) => {
  return state
}
const mapDispatchToProps = (dispatch) => {
  return {
    handleTodoAdd(value) {
      dispatch(Actions.addTodo(value))
    },
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(App)

```

ActionsのaddTodoをインポートし、mapDispatchToPropsの中で
**handleTodoAdd**の関数内でdispatchを用いてaddTodoを呼ぶようにします。
それらをconnectを利用してAppへPropsを渡します。
以後、ActionCreatorは同じような形で記述して行きます。

作成したActionCreatorは、以下の記述でReact側から呼び出しが可能です。

``` App.js
// ./components/App.jsx
...
  AddTasks() {
    if (!(this.state.text)) {
      return
    }
    this.props.handleTodoAdd(this.makeTasks(this.state.text))
  }
...
```

タスクを追加する部分です(makeTasksというのは、タスクにidをつけたりする関数です。)
containerからPropsとしてStateとActionCreatorが渡されるため、**this.props**でアクセスします。
this.stateというのは、基本的に面倒なhandleChangeで変化するStateです(個人的にhandleChangeといったものはRedux側で管理したくないので、残しています。)


## 2. Reducerの記述
ActionCreatorの作成、呼び出しは完了しました。
それでは実際に、書き換えるStateを作成するReducerを記述します。

``` reducer.js
// ./reducers/reducer.jsx
const initialState = {
  tasks: [],
}

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADDTASK': {
      return {
        tasks: state.tasks.concat(action.value),
      }
    }
    case 'ENDTASK': {
      return {
        tasks: action.value,
      }
    }
    case 'UPDTASK': {
      return {
        tasks: action.value,
      }
    }
    case 'DELTASK': {
      return {
        tasks: action.value,
      }
    }
    default: {
      return state
    }
  }
}

export default reducer
```

まだ、ADDTASKの部分だけですが、stateが現在のStateになります。
それに、concat(結合)を利用することで現在のStateを更新することなく、Storeへタスクを追加した値を渡すため書き換えることが可能です。
オブジェクトの場合はObject.Assignとかを利用します。


これで、React側でthi.propsよりhandleTodoAddを呼び出すことで、ActionCreatorのaddTodoが呼び出されStateのTasksに新しいTodoが追加されます。

# React-Todo Redux版
下記のリポジトリでご確認ください。
[React-Todo Redux版](https://github.com/gcmae/react-todo/tree/react-todo-redux)

# 後書き
Reactはその特性上、いろんなことができそうですが
大規模な案件、子コンポーネントが増えてしまうとそれだけStateが増えてしまいReduxの導入が必須になってきます。
導入してみれば意外と簡単で、何より、ActionCreatorを呼ぶことでいわば、どこからでもStateの更新が可能なのでとても便利です。
小規模な場合は問題ないかもしれませんが、大規模なプロジェクトでは導入をオススメします。