Vue.js、テンプレートで書くか?描画関数で書くか?


結論は「好みによる」となることが読めていますが、それでも比較してみたい。
どちらも「DOMと状態の関係性を表す」という役割は同じですが、それぞれどんなメリット・デメリットがあるかを考えてみます。
※描画関数使う場合はみんなJSX使うよね?と思い込んでいるためJSX前提で話します。

そもそもの書き方の違い

初めに書き方の違いを軽く見てみましょう。
message という文字列を表示するだけの簡単なコンポーネントを書いてみます。

テンプレートで書く場合は下記のようになります。

<template>
  <h1>{{message}}</h1>
</template>
<script>
export default {
  data() {
    return {
      message: "Hello"
    };
  }
};
</script>

対して描画関数で書く場合は下記のようにDOMを関数内に記述します。


export default {
  data() {
    return {
      message: "Hello"
    };
  },
  render(h) {
    return <h1>{this.message}</h1>;
  }
};

違いとしては「テンプレートは静的で描画関数は動的」という点です。
そもそもテンプレートでは飽き足らず、描画関数が必要になった理由が「動的にDOMを書けることによって、複雑な描画ロジックも楽に書けるようにするため」です。
※描画関数が実用的になる例はドキュメントにいい例があるのでよければご参照ください。

このようにテンプレートではDOMの部分はJSと切り分けてHTMLを書くことができますが(実際にはVDOMにコンパイルされますが)、描画関数を使う場合はJSオブジェクトとしてDOMを記述します。

それでは、基本的な書き方の違いを見た所でどんな観点が書き方を選ぶ際に重要になりそうかを考えていきたいと思います。

1. マークアップを活かしやすいかどうか

描画関数と比較するとテンプレートで書く場合は既存のテンプレートなりデザイナーさんが書いてくれたマークアップなりをコードに移しやすいです。

Vueのテンプレートは基本的にどんなHTMLパーサーでもパース可能であるため、あまり手を加えずに移行できます。対してJSXで書く際にはモノによりますが、JSのコードが入ってきたり、一コンポーネント内にHTMLとJSが同居していたりするので、比較すると一手間かかります。

チームでの仕事のスタイルによってこの観点は重要だったりそうで無くなったりしますが、より伝統的なHTMLの書き方に近いという意味ではテンプレートに分があるでしょう。

2. Vue独自のディレクティブを活かすか vs. プログラマブルに書くか

そもそもの描画関数で書く利点はプログラマブルにDOMを生成することができることによって、複雑な描画ロジックを簡素に書けることです。この利点の裏返しとして v-xxx などのVue独自のディレクティブは軒並み利用できなくなります。

例えば v-model を使いたい場合


export default {
  data() {
    return {
      text: ""
    };
  },
  render(h) {
    return (
      <div>
        <input type="text" v-model={this.text} />
        {this.text}
      </div>
    )
  }
};

みたいには書いてもtextの値は変更されません。自前で想定通りのことを実装しようとすると下記のようになります。


export default {
  data() {
    return {
      text: ""
    };
  },
  methods: {
    updateText: function(e) {
      this.text = e.target.value;
    }
  },
  render(h) {
    return (
      <div>
        <input type="text" onChange={this.updateText} />
        {this.text}
      </div>
    );
  }
};

う〜ん車輪の再発明感がすごい!⚙

このため描画関数をメインで使う場合はVueの良さを殺しかねないので、そこは注意かなと思いました。Reactライクにfunctionalに書いていきたいという思いが強ければそっちに倒してもいいかもしれません。(それなら最初からReact使った方がいい気もする)

ただbabelのプラグインを駆使すればいくつかの種類のVueディレクティブをJSXと共に使えるようです。もしくはこれを機に自分でプラグイン作ってOSS貢献もアリかもしれません💪

例: たまたま見つけたv-modelをJSXと共に使えるようにするプラグイン

3. 型の恩恵を受けられるかどうか

型を使うことが一般化してきたフロントエンド界隈ですが、現状(2018年2月末時点)ではテンプレート内で扱う変数に対して、TypeScriptなどを用いた型をスマートに適用する方法がありません。

対して描画関数を使う場合は、当然の事ながらDOMの部分はJSオブジェクトなので、手間なく型を加えることができます。

世のVue + TypeScript構成で書いている人はこの問題どう立ち向かっているのか、というかそもそもこれを問題と考えているかが気になる…。

※ 勝手に紹介してしまいますが、コンパイル時に型チェックをしてくれるツールを作ってくださった方がいました。
Vue のテンプレートの型チェックについて

まとめ

まとめるとそれぞれを比較した際のメリットは以下になります

  • テンプレートのメリット

    • マークアップからコードに反映しやすい
    • Vueの独自ディレクティブがそのまま使える
  • 描画関数のメリット

    • プログラマブルに書ける
    • 型の恩恵を受けやすい

個人的にはVueのディレクティブを使いたい且つプラグインまみれになるのもなんだかなぁと思ったので、基本はテンプレートで書いて、描画関数使わないと厳しいような複雑な描画ロジックのコンポーネントが現れた時だけ描画関数を使う、というスタンスで行こうと思いました。

それでは、良いVueライフを!!

(記事の本筋とは関係ないですがJSXのシンタックスハイライト付いてて地味に感動しました)