JqueryでFlux(っぽいもの)

をつくるとどうなるのかと思い作ってみた。
jqueryからいきなりreact+flux+es6に行くとあらゆるものが変わってしまうので、
こういう試しも比較する上で面白いのではないかと。

## つくるものの要件

クッキークリッカー的にカウンターが

- ボタンをクリックしたらカウンター+1
- 1秒ごとに+1
- カウンターの値を30消費してlevel2にアップデートできる
- level2だとカウンターが2づつ増える

### スクショ

![jquery-flux.png](https://qiita-image-store.s3.amazonaws.com/0/30168/07343048-19a1-45d6-2685-565acf33f5e7.png)

## HTML

htmlは以下のような感じ
jqueryとオブジェクトの更新に_.extend()を使いたいのでunderscore.jsを読み込む

```index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>JQueryでFlux</title>
</head>
<body>
  <div class="wrapper">
    <div><label>Cookie: </label><span id="value">0</span></div>
    <div>
      <button id="button">Click!</button>
    </div>
    <div>
      level: <span id="level">1</span>
    </div>
    <div>クッキーを30使いアップデートする <button id="update">Update!</button></div>
  </div>
  <script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js'></script>
  <script src='/js/script.js'></script>
</body>
</html>
```

## 非Fluxの雑な例

```script.js
$(function() {
  $('#button').on('click', function(e) {
    increaseCount();
  });
  setInterval(function() {
    increaseCount();
  }, 1000);
  function increaseCount() {
    var newValue = parseInt($('#value').html(), 10) + 1;
    $('#value').html(newValue);
  }
});

```

## Flux

Fluxの場合
上記との違い

### storeを定義する。
   
つまりDOMに状態を持たせない。
さらに言うとDOMから値を取得しない。

### ViewはActionを発行する

適当にJqueryのカスタムイベントを発行する

### Actionを受け取る

Actionを受け取り、storeを更新。
更新したら必ずstoreのchangeイベントを発行する。

### Viewを更新する。

storeのchangeイベントをトリガーにhtmlを書き換える

```script.js
$(function() {
  // Store定義
  var store = {
    cookie: 0,
    level: 1
  };
  // Storeの値は必ずこの関数から取得
  function getStore(key) {
    return  store[key];
  }
  // Storeの値は必ずこの関数を通して更新
  function updateStore(newState) {
    // 現在のStoreに新しい値をマージした新オブジェクトを作成、代入する
    store = _.extend({}, store, newState);
    // update時にchangeイベントを発行する。changeイベントを発行するのはここのみ
    $(window).trigger('store:change');
  }

  // ViewはStore(store:changeイベント)を購読する　Viewの更新はここでのみ行う
  $(window).on('store:change', function() {
    $('#value').html(getStore('cookie'));
    $('#level').html(getStore('level'));
  });
  // ここまでがフレームワークと言えるものかもしれない

  // View(html)からActionの発行(Actionをtriggerするのがこのブロックの仕事)
  $('#button').on('click', function() {
    $(window).trigger('action:increase');
  });
  setInterval(function() {
    $(window).trigger('action:increase');
  }, 1000);

  $('#update').on('click', function() {
    $(window).trigger('action:requestUpdate');
  });

  // Actionを受け取ってupdateStore()するのがこのブロックの仕事
  $(window).on('action:increase', function() {
    increaseCount();
  });
  function increaseCount() {
    var amount = 1;
    if(getStore('level') === 2) {
      amount = 2;
    }
    updateStore({cookie: getStore('cookie') + amount});
  }
  function decreaseCount(amount) {
    updateStore({cookie: getStore('cookie') - amount});
  }

  $(window).on('action:requestUpdate', function() {
    if(getStore('level') === 1 && getStore('cookie') > 30) {
      decreaseCount(30);
      increaseLevel();
    }
  });
  function increaseLevel() {
    updateStore({level: getStore('level') + 1});
  }
});
```