模写で"なんとなく"理解する React-Redux超基礎

理論そっちのけで、とりあえず簡単なアプリを作ってみます。

# 今回作るもの
なんてことのない、ただのカウントアプリです↓

![giphy.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231086/c110c733-fdca-2638-7c2e-f33040151e0a.gif)

# 注意点
ただ模写していく事で「**あ、なんとなく書けるかも**」と思えることが目的です。
理論などの説明は下記リンク群が大変参考になりました。

- [Redux入門【ダイジェスト版】10分で理解するReduxの基礎](https://qiita.com/kitagawamac/items/49a1f03445b19cf407b7)
- [ざっくり React with Redux チュートリアル](https://qiita.com/pullphone/items/d28baeb296666a4847b8)
- [React+Redux入門](https://qiita.com/erukiti/items/e16aa13ad81d5938374e)

全くつかめていない方は、これらを見てから書いてみるとわかりやすいと思います。

# 開発環境

|      カテゴリ      |      バージョン 　　 |
|:----------------:|:----------------:|
| OS               |macOS Mojave 10.14.4 |
| Node.js           |            10.15.3 |
| Yarn             |              1.13.0 |
| React           |            16.8.6 |
| Redux             |              4.0.1 |


# 模写の準備

## 開発環境の構築

### Node.js, Yarnのインストール
ここの説明は省略します。
わからない人は、このQiitaが懇切丁寧です。

- [nodebrew,npm,yarnなどNode.js関連をざっくり学びながらインストール【初学者向け】](https://qiita.com/nt_tn/items/972a40ee56a67f2a74cb)

### create-react-appのインストール

Facebook社が作ってくださった「create-react-app」という雛形をダウンロードします。

```
$ yarn global add create-react-app

※"./path/to/applciation"の部分で作成するアプリケーションへのパスを指定
$ create-react-app ./path/to/application
```


このような、React自身やその他諸々のライブラリをまとめて、雛形を作成してくれるツールを「boilerplate」と言います。

色々な種類がありますので、気になる方はこちらを参考に。

- [React初心者にオススメの、最新ボイラープレート11選](https://goworkship.com/magazine/react-boilerplates/)


実際に雛形が作成され、下記のようなフォルダ・ファイル群が生成されます↓

```
.
├── README.md
├── node_modules
├── package.json
├── public
├── src
└── yarn.lock
```

とりあえず起動してみましょう。Reactのロゴがブラウザで表示されれば成功です。

```
$ yarn start
```

### Redux, react-reduxのインストール
ちなみにreact-reduxはReactとReduxの仲介役を担っているモジュールです。

```
$ yarn add redux react-redux
```

これで開発環境は構築できました。

## ファイル構成を整える
`src`ディレクトリの配下をこんな感じにしておきましょう。
あらかじめフォルダやファイルを作っていくことで、模写がラクになります。

```
├── App.css
├── App.test.js
├── actions
│   └── index.js
├── components
│   └── App.js
├── index.js
├── reducers
│   ├── count.js
│   └── index.js
└── serviceWorker.js
```

# レッツ模写！

## Actionの定義
storeにメッセージを送るためのActionを定義します。

カウントアプリは「+」と「-」ボタンによって状態を変化させるだけですので、必要なアクションは2つのみとなります。

```acitons/index.js
export const INCREMENT = 'INCREMENT'
export const DECREMENT = 'DECREMENT'

// 書き方が2通りありますが、どちらでも問題ないです
export const increment = () => {
  return {
    type: INCREMENT
  }
}

export const decrement = () => ({
  type: DECREMENT
)}
```


## Reducerの実装

storeから送られた情報をもとにstateを実際に変更する「Reducer」を実装しましょう。

### index.jsの実装
Reducer群を管理する`index.js`を実装します。

今回作成するアプリは1つのReducerしか持たないので、count.jsと分離する必要はありません。
ただ、規模の大きいアプリの場合は必要となりますので、今後の為にもやっておきましょう。

```reducers/index.js
import { combineReducers } from 'redux'
import count from './count'

export default combineReducers(({ count }))
```

### count.jsの実装
カウンターの数字を変更する部分となります。
storeから送られる情報の中の`action.type`によって、数字を増やすのか・減らすのかを決めています。

```reducers/count.js
import { INCREMENT, DECREMENT } from '../actions'

//コンポーネントの初期値を設定
const initialState = { value: 0 }

export default (state = initialState, action) => {
  switch (action.type) {
    case INCREMENT:
      return { value: state.value + 1 }
    case DECREMENT:
      return { value: state.value - 1 }
    default:
      return state
  }
}
```

## storeの実装
実装されたReducerをもとに、storeを作成します。

```index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'

import reducer from './reducers'
import App from './components'
import * as serviceWorker from './serviceWorker'

// 作成されたReducerをもとにstoreを作成
// アプリケーション内部の全てのstateは、このstateに集約される
const store = createStore(reducer)

// Providerによって、storeがどのコンポーネントからも参照できるようになる
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

serviceWorker.unregister();
```

## コンポーネントの実装
`index.js`で呼び出している「App」コンポーネントを実装しましょう。

```components/App.js
import React, { Component } from 'react'
import { connect } from 'react-redux'

import { increment, decrement } from '../actions'

class App extends Component {
  render() {
    const props = this.props
    return (
      <React.Fragment>
        <div>count:{props.value}</div>
        <button onClick={props.increment}>+</button>
        <button onClick={props.decrement}>-</button>
      </React.Fragment>
    );
  }
}

// stateから必要な情報をコンポーネントにマッピングする関数
const mapStateToProps = state => ({ value: state.count.value })

// dispatch関数をコンポーネントにマッピングする関数
const mapDispatchToProps = dispatch => ({
  increment: () => dispatch(increment()),
  decrement: () => dispatch(decrement())
})

// こんな書き方もある↓
// const mapDispatchToProps = ({ increment, decrement })

// stateとacitonをコンポーネントに関連づける
export default connect(mapStateToProps, mapDispatchToProps)(App)
```

# 次は...

TODOリストや、Ajax通信を実装してみるといいかもしれません。

- [【React】ToDoアプリを作ってみよう【前編】](https://qiita.com/mikan3rd/items/20152cdd63a708264a9e)
- [React + ReduxでREST APIを叩いてリスト表示する方法](https://qiita.com/kazmaw/items/a2def8978127ffb11f92)