ReactのチュートリアルをReduxに書き換える！ (1)


いまさらですが，ReactのチュートリアルをReduxに書き換えてみました．
今のチュートリアルは，三目並べを実装しているものです．
※チュートリアルを理解できている前提とします．

ソースコードは[Github](https://github.com/hacks-KS/React_Redux_BoardGame)にあります．

以下のサイトを読むと理解しやすいと思います．

React.js Tutorial
https://facebook.github.io/react/tutorial/tutorial.html

Redux
http://redux.js.org/

 
# Actionの作成
簡単にいうとReduxはReactのstate管理を行うものです．
なので，stateの変更を行う動作をActionに定義しなければなりません．

## state変更の把握
Reactでは`setState()`でstateの変更を行っているので，そこに注目します．
まずは，プレイヤーの切り替えの際のstate変更です．

```js:Tutorial
  handleClick(i) {
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    const current = history[history.length - 1];
    const squares = current.squares.slice();
    if (calculateWinner(squares) || squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext ? "X" : "O";
    this.setState({
      history: history.concat([
        {
          squares: squares
        }
      ]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext
    });
  }
```

次は，過去の盤面にアクセスした際のstate変更です．

```js:Tutorial
  jumpTo(step) {
    this.setState({
      stepNumber: step,
      xIsNext: step % 2 ? false : true
    });
  }
```
この２つがチュートリアルのstate変更になります．

## Actionの作成
state変更が把握できたらActionを作成しましょう．
state変更の動作は２つあるので，Actionも２つ作成します．

また，Actionにはstate変更に必要な引数を設定します．
`setState()`を見れば引数は分かります．

まずは，プレイヤーの切り替え(TURN_CHANGE)から見てみましょう．

```js:Tutorial
    this.setState({
      history: history.concat([
        {
          squares: squares
        }
      ]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext
    });
```

history と squares が必要だということが分かります．

次は，過去の盤面にアクセス(JUMP_HISTORY)を見てみましょう．

```js:Tutorial
    this.setState({
      stepNumber: step,
      xIsNext: step % 2 ? false : true
    });
```

stepが必要だということが分かります．

これらのことを踏まえて，Actionのソースコードはこのようになります．

```js:src/actions/action.js
export function turn_change(history, squares) {
  return {
    type: "TURN_CHANGE",
    history: history,
    squares: squares
  };
}

export function jump_history(step) {
  return {
    type: "JUMP_HISTORY",
    step: step
  };
}
```

Actionの名前は，TURN_CHANGE と JUMP_HISTORY と定義しました．

これでActionの作成が終わりました．

# Reducerの作成
次は，Reducerの作成を行います．
Reducerには，stateをどのように変更するのかを記述します．

## stateの初期設定
まずは，stateの初期値を設定しましょう．
これは，`constructor()`を見れば分かります．

```js:Tutorial
  constructor() {
    super();
    this.state = {
      history: [
        {
          squares: Array(9).fill(null)
        }
      ],
      stepNumber: 0,
      xIsNext: true
    };
  }
```

この値と同じように初期値を設定しましょう．
こんな感じになります．

```js:src/reducers/reducer.js
const initialState = {
  history: [
    {squares: Array(9).fill(null)}
  ],
  stepNumber: 0,
  xIsNext: true
}
```

## state変更の記述
次に，stateをどのように変更するのかを記述します．
これは`setState()`を見れば分かりますね．

まずは，TURN_CHANGE から見てみましょう．

```js:Tutorial
    this.setState({
      history: history.concat([
        {
          squares: squares
        }
      ]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext
    });
```

history は`history.concat([{squares: squares}])`，
stepNumber は`history.length`，
xIsNext は`!this.state.xIsNext`に変更しましょう．

次は，JUMP_HISTORY を見てみましょう．

```js:Tutorial
    this.setState({
      stepNumber: step,
      xIsNext: step % 2 ? false : true
    });
```

history は変更せず，
stepNumber は`step`，
xIsNext は`step % 2 ? false : true`に変更しましょう．

これらのことを踏まえて，Reducerのソースコードはこのようになります．

```js:src/reducers/reducer.js
const initialState = {
  history: [
    {squares: Array(9).fill(null)}
  ],
  stepNumber: 0,
  xIsNext: true
}

export default function Reducer(state=initialState, action) {
  switch(action.type){
    case "TURN_CHANGE":
      let squares = action.squares
      const Return_Turn_Value = {
        history: action.history.concat([{squares: squares}]),
        stepNumber: action.history.length,
        xIsNext: !state.xIsNext
      }
      return Return_Turn_Value;
    case "JUMP_HISTORY":
      const Return_Jump_Value = {
        history: state.history,
        stepNumber: action.step,
        xIsNext: action.step % 2 ? false : true
      }
      return Return_Jump_Value;
    default:
      return state;
  }
}
```

これでReducerの作成は終わりました．

# Storeの作成
次は，Storeの作成を行います．
Storeとは，ReducerやActionの情報からstateの保持や更新などを行います．

Storeには，redux-loggerを使っています．
stateの変更をログに出してくれます．
エラーの修正時に非常に役に立ちます．

Storeはこのようなソースコードになります．

```js:src/store/store.js
import {createStore,  applyMiddleware} from 'redux';
import Reducer from '../reducers/reducer';
import {createLogger} from 'redux-logger';

export default function configureStore() {
  const logger = createLogger({logger:console});
  const createStoreWithMiddleware = applyMiddleware(logger)(createStore);
  const store = createStoreWithMiddleware(Reducer);
  return store;
}
```

これでStoreの作成は終わりました．

# Containerの作成
次に，Containerの作成を行います．
Containerはコンポーネントにデータを渡す役割です．
ReactとReduxのつなぎ目のようなものですね．
※親コンポーネントの名前をあらかじめ決めておきましょう．

`connect()`でGameというコンポーネントにデータを渡しています．
詳しい説明は以下のサイトが分かりやすいです．
[react-redux connect](https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options)

```js:src/containers/container.js
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Game from '../components/Game.jsx';
import * as Actions from '../actions/action';

function mapStateToProps(state) {
  return state;
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators(Actions, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(Game)
```

これでContainerの作成は終わりました．

# Providerの作成
ここまでで，Redux側の実装はほぼ終わりました．
最後にProviderを作成しましょう．
Providerは，Containerで指定したコンポーネント階層の呼び出しでStoreを使えるようにします．
詳しい説明は以下のサイトが分かりやすいです．
[react-redux provider](https://github.com/reactjs/react-redux/blob/master/docs/api.md)

```js:src/provider.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import Container from './containers/container';
import configureStore from './store/store';

const store = configureStore();
const rootEl = document.getElementById('root');

ReactDOM.render(
    <Provider store={store}>
        <Container />
    </Provider>,
    rootEl
);
```

これでProviderの作成は終わりました．
ここまでで，Redux側の実装は終わりです．

# 最後に
今回はRedux側の実装のみです．
説明の少ないStore, Container, Providerは，どのアプリケーションでもソースコードはあまり変わりません．

[次回](http://qiita.com/hamburg-love/items/d1d559f584b22a4400fb)はコンポーネントを書いていきます．
コンポーネントはReactのチュートリアルとほぼ変わらないので説明することはあまりないのですが，ReactとReduxサイドで分けて書きたいので，次回に説明することにします．

# 参考資料
React.js チュートリアル
https://facebook.github.io/react/tutorial/tutorial.html

Redux
http://redux.js.org/

react-redux connect
https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options

react-redux provider
https://github.com/reactjs/react-redux/blob/master/docs/api.md