Let's start a Riot.js
Riot.jsをはじめよう!
Riot.js
-
「A React-like user interface micro-library」
-
カスタムタグを使ったシンプルなUIライブラリ
-
仮想DOM
-
単方向データフロー(親から子へ)
-
-
ひとつのコンポーネントはタグ(.tag)としてまとめる
-
ES6、Typescript、CoffeeScript、pug(jade)、LiveScript
-
サーバーサイドレンダリング
-
AMD、CommonJS、importもサポート
history of Riot.js
-
2014/4 v1.0
-
2015/1 v2.0
-
2016/7 v2.5
-
2016/8/21 v2.6
-
2016 summer v3 (coming soon!)
特徴1: Lightweight
- モバイル向き
- APIも少ないので学習コスト低
特徴2:HTMLライクな構文
-
HTML in JS
- タグ(コンポーネント)はHTMLライクな構文で記述し、最終的にはJavaScriptに変換される
- ロジックはコンポーネント内のscriptタグ内 or タグの下部に記述
- 自己終了タグがサポート、そのまま使える(<img>とか)
- classNameも不要
- pug(jade)サポート
- Scoped CSS
- そのタグ(DOM)内でのみ有効なCSSを記述できる
Riot.js サンプル
-
≠ Web Components
- 構文は似ているが違う
APIs
- カスタムタグ(テンプレート)
- {} 内に埋め込むキーワードを記述
- テンプレート内のthisは省略可
<tag>
<p>{name}</p>
<span class="{ checked: isCheck }" onclick="{onClick}">check</span>
<script>
this.name = 'foo';
this.isCheck = true;
this.onClick = () => {
// do something...
};
</script>
</tag>
APIs:メソッド構文
- メソッド構文はES5、ES2015(class)どちらでも可
this.onClick = () => {
// do something...
};
onClick(){
// do something...
};
or
APIs: Loops
- ループを記述する場合はeachを使う
<ul>
<li each="{user in users}">{user.name}</li>
</ul>
<script>
this.user = [
{ name: 'Mike' },
{ name: 'Dave' }
];
</script>
<li each="{users}">{name}</li>
変数を省略して、以下のように書くこともできる
APIs: Conditions
- 表示条件の切り替え
- if DOMそのものを表示しない
- show 「display: ''」を適応
- hide 「display: none」を適応
※ if=falseでも一度はそのタグが読み込まれてしまうので注意
(v3で改善されるらしい)
<div if={error}>
<div show={error}>
<div hide={error}>
APIs: Data flow
-
opts 渡されたデータを参照するプロパティ
- Reactでいうprops
- 受け渡すデータのキー(属性名)はすべて小文字もしくはハイフン繋ぎ(参照する場合はキャメルケースになる)※アンダースコアも一応使えるみたい
<my-parent>
<div>
<my-child data="{data}">
</div>
this.data = 'foo';
</my-parent>
<my-child>
<h1>{opts.data}</h1>
this.title = this.opts.data
</my-child>
APIs: Data flow
- parent 親のデータを参照するプロパティ
- 親コンポーネントのデータを直接参照・更新できる
- each利用時の自身のコンポーネントを参照するのによく使う
<child>
<ul>
<li each="{users}" onclick="{parent._onClick}">{name}</li>
</ul>
<script>
this.users = [...];
this._onClick = () => {
// do somethimg...
};
</script>
</child>
APIs: Data flow
- root 自身のDOMを参照するプロパティ
<child>
<ul>
<li>foo</li>
</ul>
<script>
const $li = root.querySelector('li');
</script>
</child>
APIs: Lifecycle event
- before-mount
- update
- before-unmount
- *
this.on('mount', () => {
// mount
});
this.on('update', () => {
// update
});
this.on('*', () => {
// all events
});
- mount
- updated
- unmount
APIs: Mixins
- タグに対して関数を拡張する機能
- 通常のmixin タグに対するmixin
- shared mixin グローバルに登録し、宣言されたタグのみで利用可能なmixin
- global mixin すべてのタグで利用できるmixin
// mixin
this.mixin(mixinObject);
// shared mixin
riot.mixin('mixinName', mixinObj);
// 呼びだし
this.mixin('mixinName');
// global mixin
riot.mixin(mixinObj);
APIs: Mixins
- タグに対して関数を拡張する機能
- 通常のmixin タグに対するmixin
- shared mixin グローバルに登録し、宣言されたタグのみで利用可能なmixin
- global mixin すべてのタグで利用できるmixin
// mixin
this.mixin(mixinObject);
// shared mixin
riot.mixin('mixinName', mixinObj);
// 呼びだし
this.mixin('mixinName');
// global mixin
riot.mixin(mixinObj);
APIs: Yield
- <yield>によってタグの外から別のタグ・HTMLを渡すことができる
- Reactのprops.childrenに近い
<my-tag>
<div>
<yield/>
</div>
this.title = this.opts.title;
</my-tag>
// 呼び出し
<my-tag title="this is p">
<p>{title}</p>
</my-tag>
<my-tag title="this is h1">
<h1>{title}</h1>
</my-tag>
APIs: Yield in pug
- pug(jade)で<Yield>を使いたい場合
- yieldはpugで予約語となっているため
<yield />(long hand表記)を使って記述する - how to use yield in jade #1281
- yieldはpugで予約語となっているため
my-tag
div
<yield/>
this.title = this.opts.title;
データ更新について
基本的にタグのデータ(this)は更新すると自動的にDOMが更新されるが、イベントのスコープが外れた状態(setTimeoutやxhr)でデータを更新するとレンダリング処理が走らないので、そのときは自分で`this.update()`を呼ぶ必要がある。
これ結構ハマる。
// 通常はこのような更新
this.items.push({ title: this.text });
// 以下の場合は自分でupdateする必要がある
fetch().then((text) => {
this.items.push({ title: text });
this.update(); // ← 必要!!!
});
その他
リンクなど
fin👶
Let's start a Riot.js
By Kyohei Rampage Tsukuda
Let's start a Riot.js
- 1,708