挫折しないで！作って学ぶ React + Redux 入門【実践】 

# はじめに
普段サーバサイドをメインでやっているのですが、つい最近プロジェクトでReactを使う機会があり、一度は挫折したReduxを使いました。
メモのつもりでしたが、
「現在Reactを触ってて、Reduxも使いたい」
「Reduxでやりたいことはなんとなく分かるけど使い方がイマイチ分からない」
って方の助けになれればと思い、React + Redux の使い方をざっとまとめました。

# Reduxとは
Reactが扱うUIのstate(状態)を管理をするためのフレームワークです。
詳しくはここでは説明しませんが、色々ググれば詳しいことは書いてあります。

# サンプル(イメージ)
今回は入力フォームにテキスト(名前)を入力して、それを出力するといったごく簡単なものです。
できる限りわかりやすいように簡単なものにしました。
![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381808/a914a86f-2ad8-f679-a90d-e9e03c417b5d.gif)
[デモページ](https://s-masakatsu.github.io/Redux-Lesson/)

# 準備(インストール)
まず、`create-react-app` でReactアプリを作成します。
続いて`redux` と`react-redux` をインストールします。

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

開発時にreduxのログを出力したい場合は、`redux-logger`もインストールします。

``` shell
$ npm install --save redux-logger
```

# 構成

``` shell
src/
 ├── components/
 │       ├── ui/
 │       │    ├── SendName.jsx
 │       │    └── GetName.jsx
 │       └── App.jsx
 ├── redux/
 │     ├── reducers/
 │     │      ├── index.js
 │     │      └── name.js
 │     ├── action.js
 │     ├── actionTypes.js
 │     ├── selectors.js
 │     └── store.js
 └── index.js
```

# Redux
## １. Actions

`Actions` は、アプリケーションからstoreにデータを送信する情報のオブジェクトです。

まずはじめにActionのタイプの名前を定義します。

``` js:~/redux/actionTypes.js
export const SEND_NAME = 'SEND_NAME' 
```

アプリケーションが大きくなることを踏まえて、別ファイルに記述しています。
今回は一つだけですが、複数のActionがある場合は複数記述してください。
Actionのタイプはあなた次第です。

続いて実際にActionを定義します。

``` js:~/redux/action.js
import { SEND_NAME } from 'redux/actionTypes'

export const sendName = name => ({
  type: SEND_NAME,
  name: name
});
```

ここで注意なのが`type`  は必ず入れてください。
あとは自分が開発するアプリケーションに合わせて定義してください。
今回は入力される名前だけなので`name` だけ定義しています。

## ２. Reducers

`Reducers` は、storeに送信されたActionsに応じてアプリケーションの状態がどのように変化するかを指定するメソッドを定義します。

まずはじめに初期状態を定義します。

``` js
const initialState = {
  name: ''
};
```

つづいてActionのタイプに応じて処理を書いていきます。
複数のActionを定義している場合はタイプに応じて処理を書いてください。

``` js
export default (state = initialState, action) => {
  switch (action.type) {
    // case Actionタイプ名
    case SEND_NAME:
      return {
        ...state,
        name: action.name
      };
    default:
      return state;
  }
}
```

まとめると下記のようになります。

``` js:~/reducers/name.js

import { SEND_NAME } from 'redux/actionTypes'

const initialState = {
  name: ''
};

export default (state = initialState, action) => {
  switch (action.type) {
    case SEND_NAME:
      return {
        ...state,
        name: action.name
      };
    default:
      return state;
  }
}
```

最後に定義したReducerを呼び出し一つのオブジェクトにします。
これもアプリケーションが大きくなることを踏まえてReducerを分けています。

``` js:~/reducers/index.js
import { combineReducers } from 'redux'
import name from 'redux/reducers/name'

export default combineReducers({name});
```

## ３. Stores

続いて`Stores` を定義します。
Reduxではstoreは必ず一つにしてください。

``` js
import { createStore } from 'redux'
import rootReducer from 'redux/reducers'

export default createStore(rootReducer);
```

もしもログを出したい場合は下記のようにしてください。
今回は開発環境のみにログを出します。

``` js:~/redux/store.js
import { createStore, applyMiddleware } from 'redux'
import rootReducer from 'redux/reducers'
import { createLogger } from 'redux-logger'

const middlewares = [];

if(process.env.NODE_ENV !== 'production') {
  const logger = createLogger({
    diff: true,
    collapsed: true,
  });
  middlewares.push(logger);
}

const store = createStore(rootReducer, applyMiddleware(...middlewares));

export default store;
```

# React + Redux

続いてReactからReduxを操作します。

## 書き込み

まずはじめに入力した値(名前)をReduxで宣言した`name` に書き込みます。
書き込む際は、

- ReactとReduxを繋ぐ為の`connect`
- 使用したいAction

を読み込みます。

``` js
import { connect } from 'react-redux'
import { sendName } from 'redux/action'
```

続いて`connect` を使いReactとReduxを繋ぎます。

``` js
connect(mapStateToProps, mapDispatchToProps)(App);
```

- 第一引数`mapStateToProps`は、componentに渡すpropsを制御します
- 第二引数の`mapDispatchToProps`は、reducerを呼び出して、reduxで管理しているstateを更新します
- `App`は、取得したデータをpropsとして扱いたいcomponentを指定します

では、さっそく書き込み用のJSXを作成します。

``` js:~/components/ui/SendName.jsx
import React, { Component }  from 'react'
import { connect } from 'react-redux'
import { sendName } from 'redux/action'

class SendName extends Component {
  constructor(props) {
    super(props);
    this.state = {name: ''};
  }

  updataName = name => {
    name = name.trim();
    this.setState({ name });
  };

  handleSendName = () => {    
    this.props.sendName(this.state.name);
    this.setState({name: ''});
  };

  render() {
    return (
      <div className={Style.form}>
        <label htmlFor='name'>
          名前
          <input type='text' onChange={e => this.updataName(e.target.value)} value={this.state.name}>
        </label>
        <button onClick={this.handleSendName}>送信</button>
      </div>
    );
  }
}

export default connect(null, {sendName})(SendName);
```

## 読み込み

まずはじめにReduxで書き込んだ値を取得する処理を書きます。

``` js:~/redux/selectors.js
export const getNameStore = store => store.name;

export const getName = store =>
  getNameStore(store) ? getNameStore(store).name : 'No Name';
```

続いてJSXを作成します。
こちらも`connect`と、先ほど作成したファイルを読み込みます。
`MapStateToProps`で取得する処理を書き、connectの第一引数で呼び出します。

``` js:~/components/ui/GetName.jsx
import React from 'react'
import { connect } from 'react-redux'
import { getName } from 'redux/selectors'

const GetName = ({name}) => {
  return (
    <p>入力された名前：{name}</p>
  );
}

const MapStateToProps = state => {
  const name = getName(state);
  return {name};
}

export default connect(MapStateToProps)(GetName);
```

これでReact + Reduxでstate(状態)を管理できます。

# さいごに
Reduxは理解するまで少し大変だと思いますが、是非手を動かしながら学んでみてください。
Reduxが使えればReactでの開発がすごく変わります！
是非トライしてみましょ！

### コード

- [Redux-Lesson【GitHub】](https://github.com/S-Masakatsu/Redux-Lesson)

### 参考

- [Reduxチュートリアル](https://redux.js.org/basics/basic-tutorial)
- [Redux入門【ダイジェスト版】10分で理解するReduxの基礎](https://qiita.com/kitagawamac/items/49a1f03445b19cf407b7)