vue-cliでvueのプロジェクトを作成し、main.jsを見た時にrender関数って何?って思った人も多いかと思います。本文書では初めてrender関数を見た時に調べたことをまとめたものでrender関数の使用方法について説明を行っています。

render関数は何をしてくれるのか

vue.jsのコンポーネントは通常templateタグの中にhtml文を記述することでブラウザ上にコンテンツを表示させることができます。render関数もtemplateタグと同様にhtml文をブラウザに表示させることができる関数です。

vue-cliで見つけたrender関数

vue-cliを使用してプロジェクトを作成後、main.jsを確認するとrender関数が利用されています。


new Vue({
  render: h => h(App),
}).$mount('#app')

最初はhが何を意味するかわかりませんでしたがhはhype Scriptの略でrender h => h(App)は下記を略した記述方法だということがわかりました。


render: function(createElement){
  return createElement(App)
}

さらにcreateElementの引数にタグや文字列を入れることで、ブラウザ上に記述した内容を表示させる機能があることがわかったので試しながら理解を深めていきます。

はじめてのrender関数

Hello World

テキストHello Worldをrender関数を利用してブラウザ上に表示させるためには以下のような記述が必要となります。createElementでは第一引数に要素名、第二引数に要素の中に入る文字列を記述しています。


<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Render Function</title>
</head>
<body>
  <div id="app">
  </div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>

var app = new Vue({
  el: '#app',
  render: function(createElement){
    return createElement('p','Hello World')
  }
})

</script> 
</body>
</html>

ブラウザで見るとHello Worldが表示されます。

render関数でHello World
render関数でHello World

render関数でデータプロパティを使う

Vueインスタンスに設定したdataも使用することができます。dataを使っても表示結果は同じです。


var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello World'
  },
  render: function(createElement){
    return createElement('h1',this.message)
  }
})

属性の設定(class, style)

classや属性の設定も行うことができます。属性を使用する場合は第二引数を使用して、第三引数が文字列になります。


render: function(createElement){
  return createElement('h1',{ class: 'hello' },this.message)
}

style属性も同様に設定可能です。


render: function(createElement){
  return createElement('h1',{ style: 'background-color:red;color:white;' },this.message)
}

v-bindを使ってclass属性の設定も行うことができます。下記ではclassのFooのみclassが適用されます。


var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello World',
    isActive: true,
    isFalse: false
  },
render: function(createElement){
  return createElement('h1',{ class: {
    foo: this.isActive,
    bar: this.isFalse
  } },this.message)
}
})

イベントの設定

clickイベントも設定を行うことができます。h1もHello Worldをクリックするとalertがポップアップします。


var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello World',
  },
  methods:{
    alert: function(){
      alert('click')
    }
  },
  render: function(createElement){
    return createElement('h1',{ on: {click: this.alert}},this.message)
  }
})

子要素の追加

1つの要素だけではなくその下に子要素も追加することができます。ulタグの下に複数のliタグを追加することもできます。


var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello World',
  },
  render: function(createElement){
    return createElement('ul',{ class: 'hello'},
      [
        createElement('li',this.message),
        createElement('li','Hello Vue')
      ]
    )
  }
})

このように属性やイベント、子要素の追加等なんでも行うことが可能です。

コンポーネントでrender関数を使う

ここで非常にシンプルな子コンポーネントを使ってrender関数の使い方を確認していきましょう。

コンポーネントHeader.vueファイルを作成します。親のコンポーネントからpropsのlevelを受け取り、render関数と受け取ったlevelを使ってh1タグの文字列をブラウザに表示させます。this.$slots.defaultは親コンポーネントから挿入されるコンテンツが入っています。


<script>
export default {
  name: 'Header',
  props: {
    level: {
      type: Number,
      required: true
    }   
  },
  render: function (createElement) {
    return createElement(
      'h' + this.level,
      this.$slots.default
    )
  },
}
</script>

親側のコンポーネントを作成します。


<template>
  <div>
  <Header :level="1">
    Render関数を理解する
  </Header>
</div>
</template>
<script>
import Header from './components/Header.vue'
export default {
  name: 'app',
  components: {
    Header,
  },
}
</script>

子コンポーネントの$this.slots.$defaultの中には、Headerタグの間に入ったテキストが入ります。子コンポーネントでもrender関数を利用できることが確認できます。

コンポーネントにrender関数を利用
コンポーネントにrender関数を利用

render関数を利用せずtemplateタグを利用した場合は下記のような記述になります。


<template>
  <h1 v-if="level === 1">
    <slot></slot>
  </h1>
</template>
<script>
export default {
  name: 'Header',
  props: {
    level: {
      type: Number,
      required: true
    }   
  },
}
</script>

コンポーネントは再利用が可能なので、h2タグに変更したい場合はどのような変更が必要かrender関数を利用する場合としない場合で比較してみましょう。

render関数を利用する場合はlevelの値を2に変更するだけであとの変更は必要ありません。


<Header :level="2">
  Render関数を理解する
</Header>

render関数を利用しない場合はifの分岐を追加する必要があります。


<template>
  <div>
    <h1 v-if="level === 1">
      <slot></slot>
    </h1>  
    <h2 v-if="level === 2">
      <slot></slot>
    </h2>
  </div>
</template>
<script>

h1, h2タグだけではなくh3, h4,..とこのコンポーネントで対応することになると明らかにrender関数を利用したほうほ効率的にコードを記述していることがわかります。render関数を使うことなんてないかもと思っていた人もこのコードを見たらrender関数に興味が湧いてきたかもしれません。実際にvue.jsのプラグインのVuetifyなどはrender関数を利用してコンポーネントの作成を行っています。

ここでは簡単な例を使って使用方法の説明を行いましたが、より詳しい説明は公式ドキュメントに記載されています。