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>を使いたい場合
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👶

Made with Slides.com