Redux + React + ES6 の簡単アプリを作成する②(ReactとReduxの連携編)

# 概要

* [前回記事](http://qiita.com/gc-fujimoto/items/547ab425f96bf7134b9d)の続き。
* 実際にReduxでReactのstateを管理する。
* Reactのインストールは出来ている前提とする。
* ReactとReactDOMはwebpackでグローバル変数かしている事とする。

# Components

ReactでComponentsを作成していく。
まずは、メインとなるComponent。
(CSSフレームワークはMaterialize.cssを利用している。)

```js:src/components/AppComponents.jsx
import FormApp from './Form/FormApp.jsx';

export default class App extends React.Component {
  render() {
    return (
      <div className="container">
        <FormApp
          handleClick={this.props.onClick}
          value={this.props.value}
        />
      </div>
    );
  }
}

App.propTypes = {
  onClick: React.PropTypes.func,
  value: React.PropTypes.string
};
```

次に、Form全体を括るComponent。

```js:src/components/Form/FormApp.jsx
import FormInput from './FormInput';
import FormDisplay from './FormDisplay';

export default class FormApp extends React.Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="row">
            <h1>Redux + React</h1>
          </div>
          <div className="row">
            <div className="col s12 m4 l4">
              <FormInput
                className="input-text"
                handleClick={this.props.handleClick}
              />
            </div>
          </div>
          <div className="row">
            <FormDisplay
              value={this.props.value}
            />
          </div>
        </div>
      </div>
    );
  }
}

FormApp.propTypes = {
  handleClick: React.PropTypes.func,
  value: React.PropTypes.string,
};

```

次は、Input部分のComponent。

```js:src/components/Form/FormInput.jsx 

export default class FormInput extends React.Component {
  constructor(props) {
    super(props);
    this.send = this.send.bind(this);
  }
  send(e) {
    e.preventDefault();
    this.props.handleClick(this.refs.inputText.value);
    this.refs.inputText.value = '';
    return;
  }
  render() {
    return (
      <form>
        <input
          type="text"
          defaultValue=""
          ref="inputText"
        />
        <button
          className="btn"
          onClick={this.send}
        >
          Send
        </button>
      </form>
    );
  }
}

FormInput.propTypes = {
  handleClick: React.PropTypes.func
};

```

最後に表示部分のComponent。

```js:src/components/Form/FormDisplay.jsx

export default class FormDisplay extends React.Component {
  render() {
    return (
      <div>{this.props.value}</div>
    );
  }
}

FormDisplay.propTypes = {
  value: React.PropTypes.string
};

```

# Container

ReduxでReactを扱う時に、最初にはまるのはContainerの作成だと思います。
Reduxを使う上では、ReactのComponentは2種類に分けられます。

## Container Components

機能に関するコンポーネント。いわゆるFluxでいうContainerです。
主に直接Reduxと連携するコンポーネントで、ReduxのStoreの状態（state）を監視し、またReduxのActionをDispatchする役割を持ち、データを所得したり、stateの更新を行ったりします。
主に親コンポーネントがこの役割を担います。

## Presentational Components

見た目に関するコンポーネント。
Container componentsからpropsを通してデータを受け取り、Viewを構築します。
また同様にpropsから受け取ったコールバックを実行します。
前述した、Componentはこちらにあたる。

Container Componentsを実装していきます。

```js:src/containers/AppContainer.jsx
import { connect } from 'react-redux';
import App from './../components/AppComponents';
import FormActions from './../actions/FormActions';


let mapStateToProps = (state) => {
  return {
    value: state.value
  };
};

let mapDispatchToProps = (dispatch) => {
  return {
    onClick(value) {
      console.log(value);
      dispatch(FormActions.send(value));
    }
  };
};

const AppContainer = connect(
  mapStateToProps,
  mapDispatchToProps
)(App);

export default AppContainer;

```

状態管理の部分はContainerComponentsで行います。
最後のconnectの部分で、PresentationalComponentsを引数にとり、ReuxとReactを連携します。

# エントリーポイント

最後にエントリーポイントを実装します。

```js:src/index.jsx
/*::::::::::::::::::::::::::::::::::
 Components
:::::::::::::::::::::::::::::::::::*/
import App from './containers/App';
import { createStore } from 'redux';
import Reducer from './reducers/App';
import { Provider } from 'react-redux';

/*::::::::::::::::::::::::::::::::::
 InitialState
:::::::::::::::::::::::::::::::::::*/
const initialState = {
  value: ''
};
/*::::::::::::::::::::::::::::::::::
 InitialStore
:::::::::::::::::::::::::::::::::::*/
const store = createStore(Reducer, initialState);

/*::::::::::::::::::::::::::::::::::
 InitialDOM
:::::::::::::::::::::::::::::::::::*/
let mountNode = document.getElementById('mountNode');

/*::::::::::::::::::::::::::::::::::
 Rendering
:::::::::::::::::::::::::::::::::::*/
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>
  , mountNode);

```

InitialStateでstateを初期化し、
InitialStoreで引数にReducerとstateの初期値を渡します。
これによりStoreが作成されます。

最後にContainerComponentsをrenderするのですが、この際にreact-reduxが提供する[Provider]コンポーネントを親としてrenderします。
Providerコンポーネントはパラメータとして、storeをとり、ここに作成したstoreを与える事で、PresentationalComponentsのpropsの値としてstateが使えるという仕組みです。

# 終わり

Redux自体は簡単なものの、ReactとReduxの連携の部分が少しデリケートで戸惑いましたが、
簡単アプリの作成に成功しました。
データがAction->(Dispatch)->Reducer->Storeと一方向になる事で、大・中規模のシステムでも対応しやすくなるのではないかと思います。
次はFluxをもう少し掘り下げての勉強と、Reduxでの非同期通信(Actionに記載?)周りを調査したいと思います。