Horizon.jsのwatch機能を使って、お手軽リアルタイムレンダリング

Horizon.jsというJavaScriptのフレームワークがあります。RethinkDB上で動く、JSのバックエンド処理のためのフレームワークです。

[http://horizon.io/](http://horizon.io/)

Horizon.jsを使うと、データをwatchすることができます。watchメソッドはRxObservableを返すので、RxObservableのsubscribeメソッドが使えたりします。


イメージ感はこんな感じ。

```js

// Horizonのインスタンス作成
const hz = new Horizon()

// RethinkDB上のmessagesテーブルのコレクションを変数に代入
const messages = hz('messages') 

hz.onReady(() => {
  // messageコレクションに変更があるたびに呼ばれる
  messages.watch().subscribe(messages => {
    console.log(messages)
  })
})
      
// RethinkDBと接続
horizon.connect() 

```

RethinkDBのmessagesテーブルに変更が加えられるたびに、messagesコレクションがコンソールに出力されます。ページのリロードはありません。


## 注意書き

まだHorizonを触り始めて間もないので、何か誤りがありましたらご指摘ください。

## 準備

RethinkDBをインストールしておきます。Homebrewからどうぞ。

[ Install RethinkDB on OS X](https://www.rethinkdb.com/docs/install/osx/)

```
$ brew install rethindb
```


あとはHorizonをインストールするだけです。

```
$ npm install -g horizon
```

## プロジェクト作成

プロジェクトを作成します。

```
$ hz init AppName(任意のプロジェクト名)

$ cd AppName
```

## 起動

Horizonのserve機能を使います。

```
$ hz serve --dev
```

App画面とRethinkDBのAdmin画面が立ち上がります。


## 作ったもの

![horizon-messages.gif](https://qiita-image-store.s3.amazonaws.com/0/77614/58677cd4-00bd-b54c-8887-82fb1a021b38.gif)

左がアプリケーション画面で、右がAdmin画面です。
クリックイベントでDBにデータを追加・削除すると、その結果がリアルタイムでレンダリングにも反映されています。

RethinkDBの性質上、他のユーザーが行った変更でもリアルタイムに反映されます。
![horizon-multiple-messages.gif](https://qiita-image-store.s3.amazonaws.com/0/77614/54849c81-9e5a-984b-de2a-2c335f60fd45.gif)


書いたコードはこちら。

```html

<!doctype html>
<html>
  <head>
    <meta charset="UTF-8">
    <script src="/horizon/horizon.js"></script>
    <script>
      // アプリの情報
      let messageIds = []

      // horizonセット・アップ
      const hz = new Horizon()
      const messages = hz('messages')

      hz.onReady(() => {
        // 親DOM
        const messagesList = document.querySelector('#messages-list')

        messages.watch().subscribe(messages => {
          // いったんクリア
          messagesList.innerHTML = ''
          messageIds = messages.map((message, index) => {

            // 子DOMの追加
            const newList = document.createElement('li')
            newList.innerText = `${message.id}: ${message.body}`
            messagesList.appendChild(newList)

            // 件数把握のためだけにidの配列を作る。
            return message.id
          })
        })

        // 追加ボタン
        const addButton = document.querySelector('#add-message')
        addButton.addEventListener('click', () => {
          messages.store({id: messageIds.length + 1, type: 'chat', body: 'Hello Horizon World!'})
        })

        // 全削除ボタン
        const removeButton = document.querySelector('#remove-message')
        removeButton.addEventListener('click', () => {
          messages.removeAll(messageIds)
          messageIds = []
        })
      });
      
      hz.connect()
    </script>
  </head>
  <body>
   <ul id="messages-list">
     <li></li>
   </ul>
   <button id="add-message">Add</button>
   <button id="remove-message">Remove</button>
  </body>
</html>
```

※クロームで動かしたので、ゴリゴリES2015で書いてしまいました。

## 所感

React, Redux, Babelを使わず、この性能。良いかもしれません。
どうせReduxのmiddlewareでaxiosなりfetchなりするのだから、Horizonを使うのも手…？
ただし、RethinkDBという技術的制約がありますが…。


## 関連

前に書いた記事です。
[RethinkDB, React.js, horizon, Webpackでつくるリアルタイムチャットアプリ
](http://qiita.com/chuck0523/items/6e253f6ee53b0f081329)