React初心者が始めるRedux入門

## Reduxとは？
stateを容易に管理するためのフレームワーク。
Reactは親コンポーネントから子コンポーネントへpropsを通してデータ（state）を渡している。
となると、親子関係にないコンポーネント間でのstateの受け渡しがかなり難しい。
→一番上のコンポーネントに全てのstateを管理し、それを子コンポーネントに順次伝えていく。

<img width="1440" alt="Screen Shot 2019-03-16 at 15.39.32.png" src="https://pol.qiita.com/files/a057101b-6d91-9630-8a0b-4865906b2d9b.png">

説明に関しては、以下のURLの記事が最も分かりやすい。
https://qiita.com/kiita312/items/49a1f03445b19cf407b7

Kindle unlimitedに入っている人は以下の本も参照。
https://www.amazon.co.jp/React-Redux%E5%85%A5%E9%96%80-React%E3%81%AF%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%91%E3%81%A9Redux%E3%81%8C%E3%82%8F%E3%81%8B%E3%82%89%E3%81%AA%E3%81%84%E3%82%84%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F%E3%81%84%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AEreact-redux%E5%85%A5%E9%96%80-%E4%B8%AD%E9%87%8E-%E4%BB%81-ebook/dp/B07DLRSV8V/ref=sr_1_7?s=digital-text&ie=UTF8&qid=1552718161&sr=1-7&keywords=react

```
根本的に、「変化」と「非同期」を"同時"にコントロールするのは人間には無理がある。
Reactはその問題に対してViewレイヤーで非同期と直接DOM操作を取り除くことで解決したけども、
state(状態)の管理は開発者に委ねられたままなので、Reduxはそこを解決するためにある。
```


### そもそもstateとは？
変数みたいなやつ（ブリボンの感覚です。）
「状態を管理するState」とかいう表現で説明されるが、正直よく分からない。
とりあえず、変数とかデータとかいう認識で（railsでいうmodelからカラムを引っ張ってくる的な）。
そのコンポーネント内でのみ使うことができる。
コンポーネント外からstateを変更することはできない。

## Reduxの流れ
１ユーザーの入力からactionを作成する
２作成されたactoinをstoreへdispatch
３actionとstateを元にreducerが新しいstateに変更する
→actionとstateをreducerに渡し、新しいstateを作成する
４新しく作られたstateをstoreに保存する
→reducerが新たなstateを作成し、storeへ保存する

## Reduxに必要な知識（ブ→ブリボン、公→公式）
・state
上述参考。

・Action
ブ：storeにdispatchを通してぶち込まれるもの。
公：アプリケーションからの情報をstoreへ送る為のオブジェクト。
　　store.dispatch()でstoreへ送られる。
ブ：store.jsで書いているものは、actionCreator。
　　そのactionCreatorから概念的なactionなるものが作成され、dispatchによりstoreへ送られる。

・Reducer
ブ：storeにdispatchされたactionとstore内のstateから新たなstateを生成してくれるやつ。
公：stateを変更してくれるもの。actionとstateから、新しいstateを作成して返すメソッドです。

```
禁止事項
・引数のstate, actionインスタンスの値を変更する
・副作用をおこす(APIを呼んだり、ルーティングを変えるなどなど)
・毎回値が変わるもの(Date.now() や Math.random())を扱う
```

・Store
ブ：Reactの各コンポーネントでデータ（state)をやり取りするためのもの。railsでいうmodelというかデータベースのようなもの。アプリケーションで１つのみ存在。

```
Storesの役割は、
・stateを保持する
・stateへアクセスするためのgetState()を提供する
・stateを更新するためのdispatch(action)を提供する
・リスナーを登録するためのsubscribe(listener)を提供する
```

・純粋関数(pure function)
ブ：何が純粋か非純粋かよく分からん。高校生か。

```
不明点
・子reducerの返したstateを親reducerがまとめて一つのツリー状のstateを返す
→「ツリー状のstate」とは？
```

## 実装
githubのコード：https://github.com/ryubb/redux-app

```
git cloneをする
redux-appのレポジトリにcdする
yarn install
yarn start
↑これで動きます
```
### 下準備
npm react-create-app [任意のアプリ名]
→reactでプロジェクト（アプリケーション）を立ち上げるコマンド
react add redux react-redux
→reduxとreact-reduxという２つのパッケージが必要
### reducer

```
import { combineReducers } from 'redux';

export function todos(state={
  list: {}
}, action) {
  switch(action.type) {
    case "ADD_TO_DO":
      // Object.assignの動きは良く分からないので、とりあえずstateを生成していると思っていてください。
      return Object.assign({}, state, {
        list: state.list.concat(action.todo)
      });
    case "REMOVE_TO_DO":
      return Object.assign({}, state, {
        list: state.list.filter(todo => {
          if(action.todo != todo) {
            return true;
          } else {
            return false;
          }
        })
      });
      default: 
      return state;
  }
}

export default combineReducers({
  todos,
});
```

### action

```
export function addToDo(todo) {
  return {
    type: 'ADD_TO_DO',
    todo
  }
}

export function removeToDo(todo) {
  return {
    type: 'REMOVE_TO_DO',
    todo
  }
}
```

### store

```
import { createStore } from 'redux';
import reducers from "./reducers";

const store = createStore(reducers);

export default store;
```

### index.js（index.htmlにバインド？している大元のファイル）

```
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './stores';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

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

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

```

### App.js（実際に実装していくファイル）

```
import React, { Component } from 'react';
import { connect } from "react-redux";
import { addToDo, removeToDo } from './actions';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  constructor(props) {
    super();
    this.state = {
      input: ""
    };
  }
  render() {
    return (
      <div className="App">
        {/* <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Edit <code>src/App.js</code> and save to reload.
          </p>
          <a
            className="App-link"
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          >
            Learn React
          </a>
        </header> */}
        <ul>
          {this.props.todos.map(todo => {
            return (
              <li key={todo}>
                <span>{todo}</span>
                <button onClick={() => this.props.onRemoveToDo(todo)}>削除</button>
              </li>
            )
          })}
        </ul>
        <input type="text" onChange={e => this.setState({input: e.target.value})} />
        <button onClick={() => this.props.onAddToDo(this.state.input)}>
          追加
        </button>
      </div>
    );
  }
}

const mapDispatchToProps = dispatch => {
  return {
    onAddToDo(todo) {
      dispatch(addToDo(todo))
    },
    onRemoveToDo(todo) {
      dispatch(removeToDo(todo))
    }
  }
};

// これを記述することで、this.props.dispatchが使える？
const mapStateToProps = state => {
  return {
    todos: state.todos.list
  }
};

export default connect(mapStateToProps, mapDispatchToProps)(App);

```