Riot.js用の状態管理ライブラリRiotx

*日本語へたくそです。すみません。
*追記 公式ウェブサイトが出てました https://cam-inc.github.io/riotx/ こっちのほうが分かり易いと思います。
Riotにも状態管理ライブラリがあった...！

# Riotx
[Riotx](https://github.com/cam-inc/riotx)は、riot.jsアプリケーション用の状態管理パターン+ライブラリです。Vuexのアーキテクチャーパターンに触発されたライブラリなのでvuexにとても似ています（下の画像を見ていただければわかると思います。
このライブラリのsrc/下のファイルが1つしかなく、約300行しかなくてとてもシンプルなのでソースコード読めば大体理解できると思います。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/206222/fd491f44-6fcc-39fa-684b-3f70164cb3b5.png)
## ざっと解説
Riotxアプリケーションの中心にあるものは、アプリケーションの状態を保持する「ストア(以下Store)」です。
Storeは基本的にアプリケーションごとに一つしか持ちません。Storeの中に下の４つが格納されています。
* **State**　　　ー アプリケーション状態の値を保持。Mutationsしか値を変更できない
* **Getters**　　ー Stateの値を返す
* **Mutations**　ー Stateの値を変更する
* **Actions** 　　 ー Mutationsを呼ぶ出す。外部通信 

##この記事で作るサンプルの完成物
(表示に時間がかかる場合があります)
<p data-height="369" data-theme-id="0" data-slug-hash="bLRyoG" data-default-tab="js,result" data-user="Elastic1" data-embed-version="2" data-pen-title="Riotx Sample" class="codepen">See the Pen <a href="https://codepen.io/Elastic1/pen/bLRyoG/">Riotx Sample</a> by jude (<a href="https://codepen.io/Elastic1">@Elastic1</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>

# やります
Riotの説明は省きます。m(_ _"m) [公式](http://riotjs.com/ja/)
まずは、riotxを手に入れましょう。
`git clone https://github.com/cam-inc/riotx.git`
`npm install riotx`
cdn経由 `<script src="https://unpkg.com/riotx@X.X.X/dist/riotx.js"></script>`
この記事ではriotx 1.X.X系を使ってます・。・

## Store
アプリケーションの中心。
`riotx.Store()`のインスタンスを生成するとStoreが作れます。引数にstate,actions,mutations,getterオブジェクトを渡せます。
そして`riotx.add(store)`でriotxにstoreを登録し、そうすることでriotxを通してstoreにアクセスできるようになります。

```javascript
const store = new riotx.Store({
  // name: string, 初期値 '@'
  state: object,  
  actions: object,
  mutations: object,
  getters: object
})

riotx.add(store)
```
riotxに複数のstoreを登録することができます。その時はnameを指定して分けますが、基本的アプリケーションにstoreは一つなのであまりやらないと思います。

## State
アプリケーションの状態が格納されたオブジェクトです。stateの値は基本的にgettersでのみ取得・mutationsでのみ変更することが推奨されています。

```javascript
const store = new riotx.Store({
  state: {
    text: 'Riot'
    lists: []
  }
})
```

## Getters
ここでStateの値を取得します。

```javascript
const store = new riotx.Store({
  state: {
    text: 'Riot'
    lists: []
  },
  //new!
  getters: {
    state: (context) => {
      return context.state
    }
  }
})

console.log(store.getter('state')) // -> { text: 'Riot', lists: [] }
```
複数の関数を登録することができ、引数にcontextとgetterを使うときに渡される値を受け取ります。`context.state`でstateを取得することができます。上のコードの場合は, `context.state.text` -> 'Riot'になりますね。
使い方は`store.getter('関数名','渡す値')`です。

## Mutations
ここでStateの値を変更します。

```javascript
const store = new riotx.Store({
  state: {
    text: 'Riot'
    lists: []
  },

  getters: {
    state: (context) => {
      return context.state
    }
  },
  //new!
  mutations: {
    updateText: (context, text) => {
      context.state.text = text
      return ['changed']
    },
    addList: (context) => {
      const text = context.state.text
      context.state.lists.push(text)
      return ['changed']
    },
    deleteList: (context) => {
      context.state.lists.pop()
      return ['changed']
    }
  },
})

store.commit('updateText', 'hoge')
store.change('changed', (state, store) => {
  console.log(state.text) // -> hoge
})
```
引数はgetter同様で,contextはstates,gettersが使えます。最後にイベントを返せばそのイベントを`store.change`で監視することができるようになります。（複数イベントを返すことができます）
デバッグでログをとっているときとかに,mutationsが非同期の処理をしていると大変らしいので、mutationsは常に同期的でなければならない。（あまりよくわかってない）
使い方は、`store.commit('関数名', '渡す値')`。


## Actions
Mutationsへ渡すデータを作成するための

```javascript
const store = new riotx.Store({
  state: {
    text: 'Riot'
    lists: []
  },

  getters: {
    state: (context) => {
      return context.state
    }
  },

  mutations: {
    updateText: (context, text) => {
      context.state.text = text
      return ['changed']
    },
    addList: (context) => {
      const text = context.state.text
      context.state.lists.push(text)
      return ['changed']
    },
    deleteList: (context) => {
      context.state.lists.pop()
      return ['changed']
    }
  },
  //new!
  actions: {
    updateText: (context, text) => {
       return Promise
        .resolve()
        .then(() => {
          context.commit('updateText', text);
        })
    },
    addList: (context) => {
      return Promise
        .resolve()
        .then(() => {
          context.commit('addList')
        })
    },
    deleteList: (context) => {
      return Promise
        .resolve()
        .then(() => {
          context.commit('deleteList')
        })
    }
  }
})

```
引数は上と同じでcontextはstate,getter,commitが使えます。mutationsは同期的でなければいけないので非同期な処理はactionで書きます。actionはstateの値を変更できないので最後にmutationsをcommitします。
Promiseを返してますが、返さなくても動きました。githubのサンプルでは常にPromiseを返してたのでそれに倣って書いてます。
使い方は`store.action('関数名', '渡す値')`

# タグ内で使ってみます。
todoもどき

```html
  <app-root>
    <h2>{ state.text }</h2>
    <input type="text" value="{ state.text }" oninput="{ onInput }" ref="str" placeholder="入力してください">
    <button onclick="{ add }">add</button>
    <button onclick="{ delete }">delete</button>
    <ul>
      <li each="{ list in state.lists }">{ list }</li>
    </ul>
    <script>
      const store = this.riotx.get(/*@*/)
    
      this.state = store.getter('state')
  
      store.change('changed', (state, store) => {
        this.state = state
        this.update()
      })
  
      this.onInput = () => {
        const str = this.refs.str.value
        store.action('updateText', str)
      }
    
      this.add = () => {
        store.action('addList')
      }
    
      this.delete = () => {
        store.action('deleteList')
      }
    </script>
  </app-root>

```
`riotx.get(store名)`でriotxに登録されたstoreを取得することができ、引数なしでデフォルトのstore名'@'が入ります。
riotxはriotのグローバルmixinに`this.riotx`を登録してるので、タグ内であればどこでも参照できます.
riot mixinの[使い方](http://riotjs.com/ja/api/#%E3%83%9F%E3%83%83%E3%82%AF%E3%82%B9%E3%82%A4%E3%83%B3)


完成物は上でcodepenで貼ってます ([こちら](https://qiita.com/jude/items/dfadc8da4cc22bddfb15#%E3%81%93%E3%81%AE%E8%A8%98%E4%BA%8B%E3%81%A7%E4%BD%9C%E3%82%8B%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%81%AE%E5%AE%8C%E6%88%90%E7%89%A9))

# 最後に
記事を書いてる途中に厳格モード・plugins機能とかが追加されたり,まだ開発は進んでいてこれから色々な機能が追加されそうです。
vuexのmoduleみたいな機能がなくて、その仕組みを自分で作るしかなさそうです。
riotxは[viron](https://qiita.com/tosaka07/items/87ef283db4b2ee19b636)というツールに使われてて、githubにあがってるのでどういう感じに使われてるかが見れます。モジュールの分け方とかがとても参考になります。


日本語難しい

# 参考文献

[Introduction・Vuex](https://vuex.vuejs.org/ja/)
[Vue.js用のFluxライクなライブラリVuexを試してみる](https://qiita.com/nasum/items/b2f11a392bf8fb125610)
https://github.com/cam-inc/viron