Riot.js ことはじめ

端的に結論を言うと、もうこれで良いじゃないかな、です。

背景
======

ちょっと前に[このへん](http://anond.hatelabo.jp/20160521163144)とかを中心にWebのフロントエンドを作るのにフレームワークはいるかいらないかみたいな議論（適当）がありましたが、業務で静的データを使ったWebページ（サーバサイドの状態がフロントエンド側から変化しないページ）を作ることが多い自分としてはこう思いました。

- 確かにjQueryで直接DOMをいじるのは、いじる要素が片手で数えられるうちはいいが、それを超えるとうまく管理できなくなるからあんまり上手い方法でないのは同意できる
- かといってReactJSは確かに便利そうではあるが、正直ぱっと見ではよくわからないので、使うなら腰を入れて勉強する必要がありそう＝ミニマムスタートしにくそう

ということでうまく折衷案的なものはないかと思っていたら riot.js というのを見つけたので試してみました。


Riot.jsの超入門
=========

Riot.jsでできる基本的な機能をまとめてみました。ちなみにこの記事のサンプルはほぼ[とりあえず試してみたいって方のための Riot.js 入門](http://phiary.me/riotjs-tutorial-try/)を参考に写経させてもらったものです。

基本形
----------------

最小構成のサンプルです。

```html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <script src='https://cdnjs.cloudflare.com/ajax/libs/riot/2.3.18/riot+compiler.js'></script>
    <title>RiotJS Test</title>
  </head>
  <body>
    <!-- タグを展開する場所 -->
    <item name='Annoy-o-Tron' quote='Hello, Hello, Hello' ></item>

    <!-- タグの定義 -->
    <script type="riot/tag">
      <item>
        <h1>{ name }</h1>
        <p>{ quote }</p>

        this.name   = opts.name;
        this.quote = opts.quote;
      </item>
    </script>

    <script>
      // マウント
      riot.mount('*');
    </script>
  </body>
</html>
```

これが以下のように展開されます。

<img width="409" alt="Screen Shot 2016-06-19 at 1.23.53 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/27627/96d1d3f7-9376-83d3-3c38-ef96c08ff221.png">

複数要素を展開する場合は`<item>`を足せばOKです。(bodyの中だけ記述)

```html
  <body>
    <item name='Annoy-o-Tron' quote='Hello, Hello, Hello' ></item>
    <item name='Northshire Cleric' quote='Is someone injured?' ></item>

    <script type="riot/tag">
      <item>
        <h1>{ name }</h1>
        <p>{ quote }</p>

	      this.name  = opts.name;
	      this.quote = opts.quote;
      </item>
    </script>

    <script>
      riot.mount('*');
    </script>
  </body>
```

この例の `<item>`タグを**カスタムタグ**と呼びます。Riot.jsのユーザインターフェースの構成要素になります。

また、複数の要素を展開したいときは、script内でループを記述することもできます。

```html
  <body>
    <item></item>
    <script type="riot/tag">
      <item>
        <!-- this.item_list を {item_list} として each属性で指定 -->
        <div each='{item_list}'>
          <h1>{ name }</h1>
          <p>{ quote }</p>
        </div>

        // JS内で要素のデータを定義する
        this.item_list = [
          {name: 'Annoy-o-Tron', quote: 'Hello, Hello, Hello'},
          {name: 'Northshire Cleric', quote: 'Is someone injured?'},
        ]
      </item>
    </script>

    <script>
      riot.mount('*');
    </script>
  </body>
```

同じように展開されます。

<img width="361" alt="Screen Shot 2016-06-19 at 2.05.51 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/27627/d1671daa-78f4-e4d3-e4f9-482f490b5da9.png">


イベント処理
----------------

カスタムタグ内のイベントハンドラもカスタムタグの定義内に書くことができます。以下、さきほどのサンプルにbuttonをつけてみた例です。

```html
  <body>
    <item></item>
    <script type="riot/tag">
      <item>
        <div each='{item_list}'>
          <h1>{ name }</h1>
          <p>{ quote }</p>
          <button onclick='{clicked}'>play</button>
        </div>

        // JS内で要素のデータを定義する
        this.item_list = [
          {name: 'Annoy-o-Tron', quote: 'Hello, Hello, Hello'},
          {name: 'Northshire Cleric', quote: 'Is someone injured?'},
        ]

        // イベントハンドラを定義
        this.clicked = function(e) {
          console.log(e);
          console.log(`played ${this.name}`);
        }
      </item>
    </script>

    <script>
      riot.mount('*');
    </script>
  </body>
```

`this.clicked`に格納したイベントハンドラをbuttonのクリック時に呼び出しています。thisはイベント発火時の要素が入るので、`this.name`で名前を取得することができます。以下、下のボタンをクリックした時の出力例です。

<img width="632" alt="Screen Shot 2016-06-19 at 2.11.20 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/27627/66d30f2b-40a4-800e-f2e5-b5613cfb28d3.png">

個別CSSの記述
----------------

カスタム内部だけに有効なCSSを定義することができます。これによっていままで分断されていたHTML、CSS、JavaScriptを小さいスコープで一括管理できるようになります。個人的にはこれは非常に強力だと思います。

カスタムタグ内に`style`タグを使って定義しますが、タグ記述の際に`<style scoped>`と記述すること、対象となるCSSに `:scope` を記述します。

```html
  <body>
    <item></item>
    <p>ここのpタグは影響をうけない</p>

    <script type="riot/tag">
      <item>
        <div each='{item_list}'>
          <h1>{ name }</h1>
          <p>{ quote }</p>
        </div>

        <style scoped>
          :scope p {
            color: red;
          }
        </style>

        this.item_list = [
          {name: 'Annoy-o-Tron', quote: 'Hello, Hello, Hello'},
        ];
      </item>
    </script>

    <script>
      riot.mount('*');
    </script>
  </body>
```


表示の更新
----------------

Riot.jsは再レンダリングするタイミングが幾つかあります。以下に例を示します。

```html
  <body>
    <item></item>

    <script type="riot/tag">
      <item>
    	  <button onclick='{add}'>add</button>
        <div each='{item_list}'>
          <h2>{ name }</h2>
        </div>

        this.item_list = [];

        this.add = function(e) {
          this.item_list.push({ name: '要素' + this.item_list.length });
        }

        const self = this;
        setInterval(function() {
          self.item_list.push({name: 'tick'});
          self.update();
        }, 1000);
      </item>
    </script>

    <script>
      riot.mount('*');
    </script>
  </body>
```

1つがイベントハンドラが呼び出された時なので、`this.add` が呼び出された時は特に指定をしなくても `this.item_list` に追加したデータを表示してくれます。

一方、`setInterval`で一秒ごとにデータを追加していますが、これはイベントハンドラの呼び出しではないので、明示的に対象要素の `this.update()` を呼び出す必要があります。上記サンプル中では、setInterval内ではthisが対象要素ではなくなってしまうため、selfに格納させてそこから参照しています。

数秒ぐらいにaddボタンを押すと以下のようになります。

<img width="154" alt="Screen Shot 2016-06-19 at 2.45.49 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/27627/23039355-9635-cb6e-f43f-daf49bcc0767.png">

Riot.js のよさ・注意
======================

正直なところ自分はReactやAngularなど、他のフレームワークであまり開発した経験がないので Riot.js について直感的に思ったところを述べます。

シンプル
-----------

直感的に思ったのが使い方がシンプルだということです。HTML, CSS, JavaScriptを知っている人がドキュメントを見ずにコードだけを見て「あ、こういう感じに動くんだろうな」という想像がつきます。他フレームワークでも同じことができるとは思いますし、シンプルということは複雑な処理がしにくいということかもしれませんが、同じ機能をつかうだけなら学習コスト、保守などの観点からシンプルさは正義です。


分割統治
---------------

正直自分としてはこれが一番よさを感じました。ReactでもpracticalにCSSを内包させる書き方もあるみたいですが、Riot.jsだと標準的にHTML + JS + CSSをコンポーネント化できて、しかもネストもできるようです。

ある程度のコンテンツ量になってくると、どうしてもCSSやJSがとっちらかってきてしまい、統制するためにはある程度の頑張りが必要になります。エンジニアたるものちゃんと統制しろという話はもちろんありますが、頑張らなくていいことは頑張りたくないのが人情です。スコープを分割してシンプルにまとめることで保守がしやすくなり、可搬性も高くなるというメリットは大きいと思います。


アップデートの早さ
------------

一方注意したい点というべきか、本来は良い点と捉えるべきなのかもしれませんが、まだマチュアではない部分が多いようです。ちゃんと追えていませんが、記述方法などもちょいちょい変更が入っているようですし、（自分が悪いだけかもしれませんが）公式ドキュメントに書いてあるやりかただと動かない…みたいなこともちょいちょい。なので、使う場合は特にバージョンとの整合性などに気をつけたほうがいいかもです。


まとめ
===========

ということで、個人的にはかなり気に入りました。

次に何かフロントエンドを作成する時にはぜひ採用してみたいと考えています。

参考文献
=========

- [A React-like user interface micro-library(公式)](http://riotjs.com/)
- [Riot.js 2.0 を触ってみた — まだReactで消耗しているの?](http://qiita.com/cognitom/items/fb1295f3f93911e9e92d)
- [とりあえず試してみたいって方のための Riot.js 入門](http://phiary.me/riotjs-tutorial-try/)
- [Riot 2.0を試してみる（Custom tags編](http://qiita.com/kazusa-qooq/items/674596601636b8e20023)