Riot.jsとeach属性の愉快な仲間たち


これは Riot.js Advent Calendar 2016 の15日目の記事であり, 煽り記事である.

Riot.js Advent Calendar 2016 - Qiita

また 東京理科大学 Advent Calendar 2016 の14日目の記事でもある.

東京理科大学 Advent Calendar 2016 - Qiita

なお, 私は東京理科大学の学生 ではない のだが, 縁があって『神楽坂一丁目通信局』というサークルに邪魔している. 『神楽坂一丁目通信局』には, ここで紹介するような技術を取り扱っている人間がいる (はずだ) .

Riot.jsは極めて軽量なWebクライアントサイドフレームワークである. 容量で見たらRiot.jsより軽量なのはMithrilぐらいしかない. また, Mithrilと違ってHTML風の構文で記述できる.

私はその小ささと構文が気に入って, 神楽坂一丁目通信局内で利用しているシステムの後継の開発にRiot.jsを使用している. しかし, 最近Riot.jsの each属性における不可解な振る舞いに気づいて驚いた.

each属性とは

each属性により, 配列をイテレートすることができる.

<p each={a}>
  {m}
</p>
<script>
  this.a = [{m: "v"}, {m: "w"}];
</script>

これは次のようになる.

<p>
  v
</p>
<p>
  w
</p>

tagとparent

もう一つ, tagとparentを紹介する.

<child-tag>
  <p><yield><yield></p>
  <p>World!</p>
</child-tag>

<parent-tag>
  <child-tag>{parent.m}</child-tag>
  <p>Riot.js</p>
  <script>this.m = 'Hello';</script>
</parent-tag>

これは次のようになる.

<parent-tag>
  <child-tag>
    <p>Hello</p>
    <p>World!</p>
  </child-tag>
  <p>Riot.js</p>
</parent-tag>

実にわかりやすい.

each属性の謎, スコープ

では次の例を見てみよう. Riot.jsの記述は非常にわかりやすい. 初心者でもその内容は理解できるはずだ.

<child>
  <yield></yield>
</child>

<my-tag>
  <div>
    <virtual each={a}>
      <child>
        <h1>parent.message in a tag in a loop</h1>
        <p>{parent.message}</p>
        <h1>parent.m in a tag in a loop</h1>
        <p>{parent.m}</p>
      </child>
      <div>
        <h1>parent.message in a loop</h1>
        <p>{parent.message}</p>
        <h1>m in a loop</h1>
        <p>{m}</p>
      </div>
      <div>
        <h1>message in a loop</h1>
        <p>{message}</p>
      </div>
    </virtual>
    <div>
      <h1>message in my-tag</h1>
      <p>{message}</p>
    </div>
  </div>

  <script>
    this.a = [{m: "the value of m"}]
    this.message = 'hello there'
  </script>
</my-tag>

これは以下のようになる.

<my-tag>
  <div>
    <child>
      <h1>parent.message in a tag in a loop</h1>
      <p>hello there</p>
      <h1>parent.m in a tag in a loop</h1>
      <p>undefined</p>
    </child>
    <div>
      <h1>parent.message in a loop</h1>
      <p>hello there</p>
      <h1>m in a loop</h1>
      <p>the value of m</p>
    </div>
    <div>
      <h1>message in a loop</h1>
      <p>hello there</p>
    </div>
    <div>
      <h1>message in my-tag</h1>
      <p>hello there</p>
    </div>
  </div>
</my-tag>

なるほど. ん?

よくよく見てみるとこれはおかしい. どうやらeachによるループの中ではparentmy-tagを指すらしい. つまり, ループの中では匿名のtagが生成されていることになる. しかし, そのtagからはmessageにアクセスできるし, 子のtagからparentを見てもイテレートしている値を参照できない. このtagは一体…?

よく分かる解説

では, この現象を解説しよう. ループ内では匿名のtagが確かに生成されている. このtagは親のtagから parentを除く プロパティを継承している. 一方で, 子のtagを作る時にはparentを匿名でないtagにするようにしているのだ.

ややこしい. 他のフレームワーク使いたくなるなあ. でもどいつもこいつも大抵クソ (偏見) だし, そのうえどれもトラック因数は1人だ. メンテナンス可能性なんてない. 諦観を持とう.

[top]