vue.jsを学び始めるライフサイクルという言葉を目にする機会が増えてきます。私がそうであったようにvue.jsを含めJavaScriptのフレームワークに触れたことがない人にとってはライフサイクルというものが何なのか理解するのが最初は非常に難しいと思います。最初はライフサイクルの中で行われているすべての処理を理解しようとせず利用頻度の高いcreated, mountedで何が行われるのかということと2つの区別がはっきりつけばライフサイクルの理解が進むかもしれません。本文書ではvue.jsのライフライクルフックcreatedとmountedの違いを要素elを使って説明していきます。

利用しているvue.jsのバージョンは2です。3についても言及しています。vue.jsはcdnを利用して使うため特別な環境の構築は必要ありません。デスクトップ等にindex.htmlファイルを作成し一緒に動作確認を行なってみてください。

下記はvue.jsの公式サイトに掲載されているライフサイクル図です。今回はこの図の中でelとライフサイクルフックcreated, mountedさらにbeforeCreateの3つのみ注目します。

vue.jsライフサイクル
vue.jsライフサイクル

ライフサイクルフックとは

created, mountedはライフサイクルフックと呼ばれ、vue.jsの初期化の中の決められたタイミングで実行される関数です。各ライフサイクルフックの中にプログラムを記述することでvue.jsの初期化の流れの中で記述したプログラムを必ず実行させることができます。

初期化とはvue.jsが使えるようになるまでのvue.jsの内部で行われる処理のことです。WindowsやMac OSが起動するときにユーザが利用できるまで少し時間がかかります。Vue.jsでも同様にユーザが利用できるまでに内部でさまざまな初期化の処理が行われます。

APIなどを利用して外部からデータを取得してブラウザに表示させたい場合は、ライフサイクルフックの中に外部からデータ取得を行うことができるaxiosライブラリ、fetch関数を利用してデータ取得のプログラムを記述しておきます。ライフサイクルフックの中にデータ取得のプログラムを記述することでvue.jsの初期化中にデータの取得を開始し取得が完了するとブラウザにそのデータ内容を表示させることができます。

elがなにか確認してみよう

Vue.jsのバージョン2を利用している場合

ライフサイクルを記述した上のライフサイクル図の中に”el”という文字列を見つけることができます。elはvue.jsインスタンスがマウントを行う要素で、elを指定した要素の中でだけvue.jsを動かすことができます。Vueをインスタンス化する際にnew Vueで下記のようにしてelプロパティに#appといった要素を特定するidの値を記述します。

要素のidはappという名前である必要はなく任意の名前をつけることができます。idの値はdiv要素に対してdiv id=”app”で設定しています。Vueのコンポーネントがそのid=”app”に挿入されることをマウントと呼びます。コンポーネントがその場所からなくなることをアンマウントと呼びます。マウントでコンポーネントがブラウザに表示され、アンマウントでブラウザ上からコンポーネントが消えます。

var app = new Vue({
  el: '#app',
  data: {

  },
})

このelが一体どのような情報を持っているのか確認してみましょう。elにはthis.$elでアクセスすることができます。thisはvueのインスタンスを表します。

button要素を作ってv-onディレクティブでclickイベントを設定し、クリックが行われたらshowElメソッドを実行しコンソールにthis.$elの中身を表示させます。


<body>
  <div id="app">
    <h1>Hello World</h1>
    <button v-on:click="showEl">show el</button>
  </div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
  el: '#app',
  data: {
  },
  methods:{
    showEl : function(){
      console.log(this.$el)
    }
  }
})
</script> 
</body>

デベロッパーツールのコンソールに<div id=”#app”></div>が表示されます。中身は、document.getElementById(‘app’)を使って取得できるものと同じです。

this.$elの中身を表示
this.$elの中身を表示

getElementById(‘app’)で取得できる要素と同じなので、showElメソッドのconsole.logの前に下記のコードを追加するとinnnerHTMLで中身を書き換えることも可能です。buttonをクリックするとHello WorldがHello Vueに書き換えられることが確認できます。


this.$el.innerHTML = "<h1>Hello Vue</h1>";

ここまでの動作確認でelはnew Vueインスタンスで指定した要素そのものであることがわかりました。

Vue.jsのバージョン3を利用している場合

本文書ではcdnにVue.jsのバージョン2を利用しています。Vue.jsのバージョン3ではVueインスタンスの作成方法が変更になっています。Vue.jsのバージョン3を利用した場合にthis.$elに何が表示されるのか確認します。


<body>
  <div id="app">
    <h1>Hello World</h1>
    <button v-on:click="showEl">show el</button>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    Vue.createApp({
      methods: {
        showEl() {
          console.log(this.$el)
        }
      },
    }).mount("#app")
  </script>
</body>

デベロッパーツールで確認するとappの要素ではなくtextと表示されます。

vue 3でのthis.$elの中身
vue 3でのthis.$elの中身

createdとmountedの違い

elの中身がわかったので、ライフサイクルフックのcreatedとmountedの違いを確認しておきましょう。createdとmountedの違いは下記のように説明されているのをよく見かけます。

createdはDOMがまだ作られていない状態で、mountedではDOMが作成された直後の状態です。

DOMの作成、未作成でライフサイクルフックの違いが別れているということなので、this.$elを使ってその違いを確認してみましょう。確認方法はシンプルでcreatedとmountedにconsole.logでthis.$elがそれぞれの状態でどのようになっているか確認するだけです。

this.$elはDOMの要素なのでDOMが作成されていないとthis.$elは存在しません。


new Vue({
  el: '#app',
  data: {
  },
  created : function(){
    console.log('created')
    console.log(this.$el)
  },
  mounted : function(){
    console.log('mounted')
    console.log(this.$el)
  }
})

createdではDOMが作成されていないので、this.$elはundefinedとなっており、mountedではDOMの作成が完成しているので<div id=”app”></div>が表示されます。

createdとmountedでのthis.$elの状態
createdとmountedでのthis.$elの状態
ライフサイクル図で記述されている通り、先にcreatedが実行され、その後mountedが実行されることも実際に動作確認を行うことで理解することができます。

これでcreated, mountedの違いがわかりました。そのため、createdの時にgetElementById(‘id’)を使ってDOMの要素を取得しようとしても取得することはできません。しかしmounted時にはDOMの作成が完了しているのでDOMの要素が取得できるためgetElementByIdだけではなくDOMに対してアクセスを行うvue.js以外のライブラリjQuery等もこの時点で使用可能となります。

createdでは何が完了しているのか

ではcreatedでは何が完了しているのでしょう。先程まではthis.$elでelの状態を確認しましたが、その中身は見えませんでした。今度はthisを使ってVueインスタンスを確認します。今回はdataにmessageプロパティの設定も行っておきます。


  el: '#app',
  data: {
    message : 'Hello World'
  },
  created : function(){
    this.message = 'Hello Vue'
    console.log('created')
    console.log(this)
  }

createdではVueインスタンスの作成が完了しているので、設定しているmessageをVueの中で確認することができます。this.messageをcreatedの中で上書きした値も反映されていることが確認できます。これでcreatedでインスタンスの作成が完了、dataオブジェクトがリアクティブになっているという説明を受けても理解することができます。

ここでのリアクティブとは値の更新を行うと更新が反映されるという認識で読み進めてください。
createdの状態でVueインスタンスを確認
createdの状態でVueインスタンスを確認

dataオブジェクトがリアクティブになっているのでcreatedの中でAPIを使ってデータ取得を開始しても取得したデータを設定することができるのでcreatedの中で外部からデータを取得しても問題がないことがわかるかと思います。このことが理解できた上で下記のようなコードを見ても納得できるかと思います。createdの中でデータプロパティusersに外部サーバから取得したデータを挿入しています。


  created :function(){
    axios.get('https://jsonplaceholder.typicode.com/usedrs')
          .then(response => this.users = response.data)
  }

createdとbeforeCreateの違い

beforeCreateでは、dataプロパティの中身を確認することができますがcreatedのようにmessageの上書きを行うことはできません。


  beforeCreate : function(){
    
    this.message = 'Hello Vue'

    console.log('beforeCreate')
    console.log(this)
}
beforeCreateでdata変更

これでbeforeCreateでインスタンスの作成が完了、dataオブジェクトがリアクティブになっていないという説明を受けても理解することができます。

ここまでの説明を読み終えるとelの理解、beforeCreate, created, mountedの3つのライフサイクルフックの違いも理解できたかと思います。ライフサイクル図には他にもさまざまなライフサイクルフックが記述されていました。今回は3つですが、それぞれのフックで行われることが異なるので違いを調べるとよりVue.jsの理解が深まると思います。