Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

現在(2.2.4)のRiot.jsのifステートメントはfalseでも実行されてしまう件とその回避法

More than 5 years have passed since last update.

Riot.jsに魅せられてしまったemadurandalさんですこんにちは。

Riot.jsいいですよね。Reactから移ってきたのですがもう戻れません。

  • 記述がとにかくシンプルかつHTMLセントリック(デザイナーさんにとっても抵抗少ない)。
  • HTMLとJavaScriptだけでなく、CSSまでコンポーネントにカプセル化できる。
  • サイズが超小さい(モバイルにも優しい)

などなど、メリットは計り知れません。ただ、まだ若いプロジェクトなので、罠もそれなりにありますね。

今回はそんな罠の一つ。表題の件です。

例えばですね。↓こういうのがあったとしましょう。

<my-app>
  <my-heavy-ui if={enable} arg={opt.foo} />

  this.enable = false;
</my-app>

これ、if=false なわけですが、実はページ上見えなくなるだけで、実際は<my-heavy-ui>は実行されてしまいます。取るに足らない小さい部品ならいいんですが、色々処理するような重たい部品だった場合は、嫌ですよね。

それに、再帰的に同じコンポーネントを使いたい場合は、ifで処理を止めようとしても、if=falseでも実行されてしまうために、結局延々とネスト処理が続いてスタックオーバーフローになってしまいます。

<my-folder>
  <my-folder if={!isLeaf()} arg={opt.foo} />  ←ifだとうまくいかない!

  this.isLeaf = function(){
    // 末尾かどうかを判定する処理
  }
</my-folder>

では、どうすればいいのか。eachステートメントを使います。

<my-app>
  <my-heavy-ui each={enable ? [true]:[]} arg={parent.opt.foo} />

  this.enable = false;
</my-app>
<my-folder>
  <my-folder each={!isLeaf() ? [true]:[]} arg={parent.opt.foo} />  
  this.isLeaf = function(){
    // 末尾かどうかを判定する処理
  }
</my-folder>

どういうことかというと、enable!isLeaf()が真の時は、要素数1(trueとか適当な値が1個入っている)の配列になるため、1個だけコンポーネントが生成されるのです。偽の場合は、空の配列なので、コンポーネントは生成されません。これで、擬似的にifっぽいことをしています。
注意点としては、eachステートメントを使うので、opts.fooparent.opts.fooにしないといけませんね。

これなら、重たい部品が実は生成されていたとか、コンポーネントの再帰がスタックオーバーフローだよウワァァァンとかいうことがなくなります。

私の場合、このやり方をするようにしてから、自作のチャットシステムの表示パフォーマンスがざっと体感で数倍〜10倍くらい速くなりました(ifを多用しまくっていたせいもありますが)。
特に、IE系はパフォーマンスの改善が顕著です。みなさま、騙されたと思ってぜひお試しを!

しかし、このifの挙動、なんなんですかね。Riot.jsのソース読んだり、Githubコミュニティに入り浸っているほど、深く足を突っ込んでいるわけでもないので、よくわかりません。

めんどくさいので、将来のバージョンでは仕様を変えて欲しいところですね。

2015/10/26追記

Riot.js公式サイトの日本語翻訳プロジェクトを主導され、ikki などのRiot拡張なども手がけていらっしゃる、国内におけるRiotの第一人者 @cognitom さんにこのifの挙動について質問したところ、こんなお答えがありました。

なるほど、そうでしたか……。
実装上のやむない理由により、今のような仕様になっているのですね。もちろん、本来のifの役割として望ましい挙動でないことは開発の方々も認識されているわけなので、いずれ解決されることを期待したいですね。

それでは、皆様もよいRiot.jsライフを!^o^/

emadurandal
泣く子も黙るQiitaポエマー。大学院でCGを研究後、東京大学のベンチャーに入社。PS3向けゲームエンジンの開発、そこからアクセンチュアグループを経て、現在はCGを専門とする株式会社GUNCY'SのCTOを勤めています。WebとCGどちらもこなします。 メイン分野:WebGL/CG/Web/ネットワーク関係 例:TypeScript、WebGL、Python、C/C++
guncys
私たちは集積した専門知識と独自の戦略で 組織やプロジェクトの課題解決をしながら顧客とともにあらゆる構想を実現化させ、 成功に導く現代版”軍師”集団です。
https://www.guncys.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away