Reduxを単体で使って動作を理解する

Reduxが何をやっているのかがわからない。
React + Reduxではない。
Redux単体だ。
Reduxについて調べるとやれReactとの連携とか、
Fluxについて高尚な演説が永遠と続く。
で、結局Reduxって何やってるの？と無限ループしてしまう。
そこでRedux以外は本当に何も使わずに簡単なアプリを作ってみる。

#どういったアプリを作るか

やみくもに作ってもしょうがないので仕様を決める。

* フォームに画像のURLを入力してSetボタンを押すとURL情報を内部に保存する
* Getボタンを押すと内部に保存されたURLの画像を表示する

Reduxの特性を活かすべく、
内部に状態を持ってビューの出し分けをすることを考える。

#HTML
まず以下のようなHTMLを用意する。

```html:index.htm
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8"/>
  <title>title</title>
</head>
<body>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.min.js"></script>
<script src="main.js"></script>
</html>
```

\<body\>タグは漢らしく空で、
CDNからreduxのjsをロードして処理の本体はmain.jsに書くという構造だ。
Reactとかnpm installとかはカケラも出てきてない。
なお以降の操作はChromeで行ってもらいたい。
ES6のコードがある程度そのまま動くので。

#初期化

```js:main.js
// 初期化
(() => {
    document.body.innerHTML = `
    <button onclick="actionSetURL(document.getElementById('url').value)">Set</button>
    <button onclick="actionGetImg()">Get</button>
    <button onclick="actionClear()">Clear</button>
    <input id="url" type="text" style="width: 600px;" />
    <div id="render"></div>
  `;
})();
```
bodyに骨格となるHTMLを直接流し込んでいるだけです。
ボタンや入力フォームの作成を行っています。
actionSetURL()ではフォームに入力された値を引数として渡していて、
actionGetImg()、actionClear()は引数なしということがわかるかと思います。
続いてこの3つの関数を書いていきます。

#Action

**Action**とは後述する**Store**を変更するための機構である。
typeは必須で他の引数は任意である。
typeは全て大文字のスネークケースで書くのが習わしらしい。
**Store**を更新したいときは**Action**を発行するのが基本パターンだ。

```js:main.js
// Action
const actionSetURL = url => url && store.dispatch({ type: 'SET_URL', url });
const actionGetImg = () => store.dispatch({ type: 'GET_IMG' });
const actionClear = () => store.dispatch({ type: 'CLEAR' });
```

#Reducer

**Reducer**とは**Action**と現在の**State**を受け取って、
新しい**State**を返す関数である。

```js:main.js
// Reducer
const reducerURL = (state = '', action) => {
  switch (action.type) {
    case 'SET_URL':
      return action.url;
    case 'CLEAR':
      return '';
    default:
      return state;
  }
}
const reducerImg = (state = false, action) => {
  switch (action.type) {
    case 'GET_IMG':
      return true;
    case 'CLEAR':
      return false;
    default:
      return state;
  }
}
```
この例だとreducerURLはstringを返していて
action.typeがSET_URLのときはフォームに入力した値を返し、
action.typeがCLEARのときは空文字を返す。
reducerImgはbool変数を返している。

## Reducerをまとめる

```js:main.js
const combineReducers = reducers => (state = {}, action) => Object.keys(reducers).reduce((nextState, key) => {
  nextState[key] = reducers[key](state[key],action);
  return nextState;
}, {});
const rootReducer = combineReducers({ reducerURL, reducerImg });
```

先の例ぐらいだと1つのReducerに書いてもいいかもしれないが、
規模が大きくなると分割する必要が出てくる。
複数のReducerをまとめるcombineReducersを書いて
1つに集約したものをrootReducerとする。

#Store、Provider、Render

**Store**とは**Reducer**で変更された**state**を保存する場所である。
Redux.createStore()に**Reducer**を入れて作成する。
providerは**state**を受け取ってHTMLを構築する関数だ。
**state**は**Reducer**経由でしか更新されない読み取り専用オブジェクトだ。
読み取りにはstoreに対してgetState()を呼べばいい。
renderはproviderで構築されたHTMLを描写する関数だ。

```js:main.js
// Store, Provider, Render
const store = Redux.createStore(rootReducer); // storeの作成
const provider = state => {
  const stateView = `
    <div>
      <div>state.reducerURL: ${state.reducerURL}</div>
      <div>state.reducerImg: ${state.reducerImg}</div>
    </div>
  `;
  const imgView = state.reducerImg ? `<img src='${state.reducerURL}' />` : '';
  return `
    <div>
      ${stateView}
      ${imgView}
    </div>
  `;
}
const render = () => { document.getElementById('render').innerHTML = provider(store.getState()); }
store.subscribe(render);
render();
```

#まとめ

以上でアプリケーションは動作する。
actionからstateが変更されるまでの流れがよくわかった気がする。
providerあたりでやっているHTMLの構築をスッキリ書けるのがReactということなのだな。