Riot.js tips - yield の使い方

phi phi on Riot.js

Riot.js には yield という仕組みがあります. これを使いこなすことで定義済みのコンポーネントの一部を柔軟に拡張することができるようになります.

今回はこの yield について, デモや図を交えて解説したいと思います.

そもそも Riot.js について知りたい方はまずこちらをどうぞ
フロント界隈で一番イケてるのは AngularJS でも React でもなく Riot.js だという話 | phiary

Riot.js の yield とは?

yield は, Riot.js のコア機能の一つで子タグに親タグから部分的に HTML を差し込むことができます.
この仕組みをうまく活用することで拡張性のある柔軟なタグ(コンポーネント)を定義することができます.

yield を使ったデモ

yield を使ったデモです. header の中身を外から指定したり, material-card タグを使う側が拡張しています.

yield デモのコード

タグ定義部分のコードになります.

<app>  
  <header>
    <h1>yield demo</h1>
  </header>

  <card>
    <yield to='header'>
      <h2>Card tag</h2>
    </yield>
    <yield to='content'>
      それは事実近頃そういう留学者というのの日をさないだ。どうしても事実に反抗学は単にある注意るうくらいにもっから始めうには料理なっなかっだって、どうにももたらすででませた。
    </yield>
    <yield to='footer'>
      <button>Agree</button>
      <button>Disagree</button>
    </yield>
  </card>

  <user-card>
    私も偶然ちょうどこの承諾家というののところが黙ったなく。いくら十一月を参考団は一々そんな道楽ますなかもに潜り込むてくるませからさえ観念考えますないから、実際には立っなでべきで。
  </user-card>

  this.hoge = 100;
</app>

<header>  
  <yield/>

  <style scoped>
    :scope {
      display: block;
      background-color: hsl(200, 80%, 70%);
      color: white;
      height: 42px;
      line-height: 42px;
      padding-left: 1rem;
    }
  </style>
</header>

<card>  
  <div class='header'>
    <yield from='header' />
  </div>
  <div class='content'>
    <yield from='content' />
  </div>
  <div class='footer'>
    <yield from='footer' />
  </div>

  <style scoped>
    :scope {
      display: block;
      background-color: white;
      margin: 16px;
      box-shadow: 0px 0px 4px 0px #aaa;
      color: #666;
      border-radius: 2px;
    }
    :scope .header {
      padding: 16px;
      padding-bottom: 0px;
    }
    :scope .header h2 {
      margin: 0;
    }
    :scope .content {
      padding: 16px;
    }
    :scope .footer {
      border-top: 1px solid rgba(0, 0, 0, 0.1);
      padding: 8px;
      text-align: right;
    }
    :scope .footer button {
      background-color: transparent;
      border: none;
      color: inherit;
      outline: none;
      cursor: pointer;
    }
  </style>
</card>

<user-card>  
  <card>
    <yield to='content'>
      <p>
        card タグを継承して, header と footer を消して色を変更してみたやつ
      </p>
      <p>
        <yield />
      </p>
    </yield>
  </card>

  <style scoped>
    :scope card {
      color: white;
      background-color: hsl(190, 80%, 45%);
    }
    :scope card .footer, :scope card .header {
      display: none;
    }
  </style>
</user-card>  

yield デモの解説

Riot.js における yield は, タグとして使います.
使い方には2通りあるのでそれぞれ解説したいと思います.

シンプルな yield タグの使い方

デモでいう header 部分にあたります.

タグ定義側に yield タグを埋め込んでおき, そのタグを使うアプリケーション側で html を渡してあげると, yield の位置にその html を展開することができます.

こうすることで下記図のように定義済みのタグを使う側で部分拡張して使うことができます.

yield と from, to 属性を組み合わせた使い方

シンプルな使い方では使う側で指定した html がそのまま <yield /> に差し込まれるのがわかったかと思います.

ですが, Riot.js を使い込んでいくと複数箇所に使い側から html を差し込みたいといった場面が出てきます. そこで使えるのが from, to 属性です.

タグ定義側で <yield from="キー名" /> と指定し, 使う側で <yield to="キー名"> とすることで それぞれ対応した場所に html を展開することができます.

デモでは card タグ部分にあたります.

マウントされると下図のような形で展開されます.

yield を使ったコンポーネント継承

デモの user-card 部分にあたります.

card タグを内包し, yield 用の html を固定で指定したり style を上書きすることで
コンポーネント継承のようなものを実現することができます.

<user-card>  
  <card>
    <yield to='content'>
      <p>
        card タグを継承して, header と footer を消して色を変更してみたやつ
      </p>
      <p>
        <yield />
      </p>
    </yield>
  </card>

  <style scoped>
    :scope card {
      color: white;
      background-color: hsl(190, 80%, 45%);
    }
    :scope card .footer, :scope card .header {
      display: none;
    }
  </style>
</user-card>  

yield を使う際の名前空間について

注意点として, yield で展開される html はあくまでタグ定義側でデータバインディングされるという点です. つまり下記ようなコードだと title は展開されません.

<app>  
  <header>
    <h1>{title}</h1>
  </header>

  this.title = 'Hello, Riot.js';
</app>  

なぜなら header タグを定義している側には title 変数がないからです.

これをちゃんと動かしたい場合は下記のようにオプションに渡して指定してあげるようにしましょう.

<app>  
  <header title='{title}'>
    <h1>{opts.title}</h1>
  </header>

  this.title = 'Hello, Riot.js';
</app>  

おわりに

正直, yield が必要になる場面って普通にサービスを作る際にはあまりはないと思います.

ですが, ちゃんと使いこなせば

  • 大規模開発でコンポーネント単位で作業を分業したり
  • Riot.js 製のコンポーネントライブラリなんかを作る際

などにとても重宝します.

私自身実際に yield を使うことでタグのライブラリ化がかなり楽になりました. Riot.js には, ほかにも様々な便利機能があるので引続き紹介していきたいと思います.