Vue.jsのcreatedとmountedの違いを実コードで理解する

Vue.jsでアプリケーションを作る際、createdmountedをよく利用する。しかし、いざ他人に違いを説明するときに「なんかわかってるつもり」だったかもと思うことがあったので調べ直した。Vue2.xも3.xも、createdmountedについてはあまり変化はないように見える。 1

3.x Lifecycle Hooks | Vue.js

2.x The Vue Instance — Vue.js

created

  • createdはコンポーネントのインスタンス生成後に呼び出される
  • datacomputedwatchイベントなどの生成は完了している
  • $el(DOM要素のプロパティ)は未生成

mounted

  • $elは生成済み
  • $elがマウント(=ブラウザにレンダリング)された直後に呼び出される

実際に動かしてみる

Vue3.xのプロジェクトで、ボタンを押すとDOM要素がカウントアップされるコンポーネントを作成した。検証方法はComplete Vue.js 3 (Inc. Composition API, Vue Router, Vuex)Lifecycle Hooksの動画を参考にした。 2

createdmountedAPIにconsole.infoを仕掛け、$elを出力する。

// 抜粋
  created() {
    console.info('created', this.$el, this.$data);
  },
  mounted() {
    console.info('mounted', this.$el, this.$data);
  },

結果

createdとmounted

createdでは$elは作成されていない。よってnullが出力される。mounted$elがマウントされた直後に呼び出されるため、$elnullではない。実際にレンダリングされているDOM要素が表示される。

その他

v-preAPIを使うとbeforeMountの前にDOM要素をレンダリングできる。Mustache記法({{}})そのものを表現したい場合などに利用する。

Vue2.x API — Vue.js

Vue3.x Built-in Directives | Vue.js

// scriptに追加
  beforeMount() {
    console.info('beforeMount', this.$el, this.$data)
  },

beforeMountとv-pre

<template>
  <div id="counter">
    <p v-pre>{{v-pre nodes}} {{count}}</p>
    <p>Click Count {{count}}</p>
  </div>
</template>

この<p>タグ要素にv-preをつけるとMustache記法がそのままDOMに変換されていることがわかる。この段階では$elはnullなのでイベントの検知はできない。

<template>
  <div id="counter">
    <p v-pre>{{v-pre nodes}} {{count}}</p>
    <p>Click Count {{count}}</p>
    <div>
      <button  v-pre @click="countUp">Click</button> ←ここは$elが生成されていないのでDOMExceptionになる
      <button class="reset-button" @click="resetCount">Reset</button>
    </div>
  </div>
</template>

beforeMountの段階ではDOMイベントを検知できない

いつ使い分けるか?

画面表示前にAPIリクエストでパラメータをもらっておく…みたいな使い方が多いのかなと思う。

createdを使うとき

サーバーサイドレンダリング(SSR)はcreatedを使う。mountedはSSRでは検知できないため。サーバーでレンダリングしたDOMを返して表示する仕組みと考えると、「それはそうかもな」と思った。また、レンダリング前に何か制御しておきたい場合もcreatedの段階で処理している。mountedだと$el生成後に発火するため、一瞬制御されない状態になってしまう。APIレスポンスパラメータに応じてルーティング先の制御をするときに使っているが、Vue RouterのbeforeEnter()でやった方がいいかもしれない。

mountedを使うとき

基本はこっちを使っている。とにかく初期描画を早くしたいので、画面をレンダリング → レスポンスパラメータが取得できるまでは代わりの何かを用意、というふうに工夫しているため。dataの初期値をnull (undefined)にしておき、「値がないときはスピナーを回す」というようにしておくとmountedでAPIリクエストをしても問題なく画面描画できる。APIレスポンスが速ければcreatedでもいいかもしれない。ただ、とにかく初期描画を早くしたい!という要件であればこのようにするのが良いかなあと思っている。

所感など

Vue3.xだとOptions APIとComposition APIがあり、Composition APIはAPI名が異なるので注意が必要。調べたところcreatedはなくsetup()になっていた。

図を見てわかったつもりになっていたが、実際に動かしてみた方が理解しやすいと改めて思った。

参考


  1. 普段はVue2.xのOptions APIなプロジェクトでやっている

  2. O'reilyの学習プラットフォームに会員登録したらPacktの動画も見放題になった。