React&Reduxエッセンシャル

#Redux&Reduxエッセンシャル
まずは，reduce,reducer,state,actionの整理
##Reduce,Reducer,State,Actionとは?
reduce     -直訳-> 変える
reducer  -直訳-> 変化を与えるもの
state -直訳-> 状態
action -直訳-> 実行
###定義
Reduceとは，***一回あたりの関数適用によって行われる値の変化***
Reducerとは，***適用される関数の事***
Stateとは，***reduceされる前の初期状態***
Actionとは，***stateをどのように変更させるか***


例）  関数 F(aを2倍にする処理を行う(Action)) 

F(2)  ->F(a)  -Reduce->4

F(2)がState,
F(a)がReducerです．




#Redux実践
##インポート

```
import { createStore } from 'redux'
```
##簡単な例
Reducerでは，Actionによって，switch文などでStateに変更を加える

```
function counter(state = 0, action) {
  switch (action.type) {
  case 'INCREMENT':
    return state + 1
  case 'DECREMENT':
    return state - 1
  default:
    return state
  }
}
```

#掲示板を作ろう
##目標
JQueryで言うと，

```
<html>
<form>
<input type="text" id="hoge" />
<button onclick="push()">追加</button>
</form>
<ul id="list"></ul>
</html>

<script>
function push(){
let sentence = $("#hoge").val() ;
$("#list").append("<li>"+sentence+"</li>") ;
}
</script>
```
![スクリーンショット 2020-02-09 9.42.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543591/f34c7f76-2335-3518-bca2-01375421cc36.png)


こんなものをReact&Reduxの基礎を踏まえながら説明．

##install
###React
npmはインストール済みの環境であることを前提とします．
※してない方は $brew install npm

```
$ npm install -g create-react-app
```

![スクリーンショット 2020-02-09 9.58.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543591/c928139a-c204-25aa-19e5-88418ace417e.png)
このようにreactをインストール

###プロジェクトの作成
```
$ create-react-app todo
```

![スクリーンショット 2020-02-09 10.04.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543591/5e2b1acc-675a-5c3c-2206-4ca1578097d6.png)

こんな感じのフォルダが出来ると思います．

```
$ cd todo
```
todoに移動しましょう．

###Redux
```
$  npm install --save redux react-redux redux-logger
```
todoフォルダにReduxのインストール
![スクリーンショット 2020-02-09 10.09.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543591/0f920658-400c-2759-9220-6e4c0ca6b0fc.png)

これで環境構築は完了．

##ディレクトリの作成
actions
components
containers
reducers
というフォルダをsrc下に配置
各フォルダ内にtodo.jsを作成しましょう．

![スクリーンショット 2020-02-09 10.14.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543591/c8a67632-232a-8295-d2dc-3a509ce795d1.png)

また，src下にcreatestore.jsというファイルも作ってください．
![スクリーンショット 2020-02-09 10.19.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543591/b64c8790-5c78-428f-a6f7-b85c5dacc558.png)

createstore.jsに関数を作ります

```
import { createStore as reduxCreateStore, applyMiddleware, combineReducers } from "redux";
import logger from "redux-logger";
import { todoReducer } from "./reducers/todo";

export default function createStore() {
  const store = reduxCreateStore(
    combineReducers({
      todo: todoReducer,
    }),
    applyMiddleware(
      logger,
    )
  );

  return store;
}

```

##ReactにReduxを適用
index.jsを変更します．

```
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

import { Provider } from 'react-redux';
import createStore from './createstore';

const store = createStore() ;

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();

```

redux,createstoreをインポートして，Providerにstoreをセットしてるだけです．

serviceWorker.unregister()とはオフラインでのキャッシュを無効にしてます．
これはcreate-react-appをすると標準でついてます．今は無視してOKです．

###Component定義
components/todo.js
todo追加用のテキストボックスとボタンを書き入れます．

```
import React from 'react';

export default class Todo extends React.Component{
  render(){
    return(
      <div>
        <input type="text" />
        <button>追加</button><br />
        <ul>
          <li>aaa</li>
          <li>bbb</li>
        </ul>
      </div>
    );
  }
}

```

![スクリーンショット 2020-02-09 10.57.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543591/8cc76254-3767-adc5-1984-f35b791a01ed.png)


##Action定義
actions/todo.js

```
export const addTodo = (todo) => {
  return {
    type: 'ADD_TODO',
    payload: { todo: todo }
  };
}
```

Actionは、Reducerに指令を出します。
type プロパティを必ず持ち、これが処理のキーになります。

payload プロパティは、処理に使うパラメータで、この例では追加するTODOを持たせています

##Reducer定義
reducer.todo.js

```
const initialState = {
  todoList: []
}

export const todoReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_TODO':
      // 新しく追加するTODO
      const todo = action.payload.todo;
      // stateを複製して追加
      const newState = Object.assign({}, state);
      newState.todoList.push(todo);
      return newState;
    default:
      return state;
  }
};
```

state は書き換えるのではなく新たなオブジェクトとするのがredux.

単純に引数のstateに追加するのではなく、

Object.assignメソッドで複製した新たな state に対して追加し、
それを戻り値とします。

##Componentの定義
components/todo.js

```
import { connect } from 'react-redux';
import * as actions from '../actions/todo';
import Todo from '../components/todo';

const mapStateToProps = state => {
  return {
    todo: state.todo,
  }
}

const mapDispatchToProps = dispatch => {
  return {
    addTodo: (todo) => dispatch(actions.addTodo(todo)),
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Todo)

```

mapStateToProps関数
使用する state を切り出して、propsで参照できるようにするための関数


mapDispatchToProps関数
dispatchするための関数をpropsにマッピングするための関数

それぞれ定義したものを、connect関数でコンポーネントに接続し、exportします。こうすることで、コンポーネントがreduxによる状態管理を意識せず、stateやdispatchを参照、実行できるようになります。

コンテナの使い方は、コンポーネントをimportしている箇所をコンテナに切り替えるのみ。
app.js

```
import React, { Component } from 'react';
import './App.css';
//import Todo from './components/todo';
import Todo from './containers/todo';
```

##Componentの書き換え
components/todo.js

```
import React from 'react';

export default class Todo extends React.Component {
  state = {
    todo: ''
  }

  render() {
    console.log(this.props);

    // StoreのTodoからリストを生成
    const list = this.props.todo.todoList.map((todo, index) => <li key={index}>{todo}</li>)

    return (
      <div>
        <input type="text" onChange={elm => this.setState({ todo: elm.target.value })} />
        <button onClick={() => this.props.addTodo(this.state.todo)}>追加</button><br />
        <ul>
          {list}
        </ul>
      </div>
    );
  }
}
```

![スクリーンショット 2020-02-09 11.25.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543591/f47dd4cd-d64e-72e2-505a-1e9d176404db.png)

冗長なコードになればなるほどreduxの恩恵が大きいです．
変更点がすぐに分かるので，チームでの開発が従来よりも簡単．