Vueのライフサイクルとは
Vueインスタンスの生成から消滅までの一連の過程のこと。
この過程における、特定のタイミングで処理を割り込ませる仕組みがライフサイクルフックと呼ばれる。
[公式ドキュメント] (https://jp.vuejs.org/v2/guide/instance.html#%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B5%E3%82%A4%E3%82%AF%E3%83%AB%E3%83%80%E3%82%A4%E3%82%A2%E3%82%B0%E3%83%A9%E3%83%A0)にざっくりと一連のフローが書いてあります。
Vue.jsでは、いくつかフックが用意されている。
コンポーネント
説明にあたって以下のようなコンポーネントを想定する。
概要は、スタイルデータを用意し、横幅が拡大するボタンを設置しただけのコード。
フック等は適宜示すので省略してます。
<template>
<div id="app" :style="appStyle">
<button @click="extendWidth">extend</button>
</div>
</template>
<script>
export default {
data () {
return {
appStyle: {
width: '120%',
height: '100%'
}
}
},
methods: {
extendWidth () {
this.appStyle.width = parseInt(this.appStyle.width) + 10 + '%'
}
}
}
</script>
beforeCreate
Vueインスタンスを生成し、データが初期化がされる前に一度だけ呼ばれるフック。
リアクティブデータが初期化される前なので、この時点でdataプロパティ等を参照しても何もありません。
beforeCreate: {
console.log(this.appStyle.width) // 'undefined'
this.extendWidth // "this.extendWidth is not a function"
}
created
Vueインスタンスを生成し、データが初期化がされた後に一度だけ呼ばれるフックです。
ここでリアクティブデータやメソッド等を参照できます。
created: {
console.log(this.appStyle.width) // '120%'
// this.extendWidth // Methods are also accessible
}
axios
を利用してAPIからデータを取得するタイミングはここがいいです。
beforeMount
VueインスタンスがDOMにマウントされる前に一度だけ呼ばれるフックです。
この時点までのライフサイクルでは、DOMの操作を行うことはできません。
beforeMount () {
// Error
console.log(this.$el.clientWidth)
},
mounted
VueインスタンスがDOMにマウントされた後に一度だけ呼ばれるフックです。
ここでDOMにアクセスできます。
mounted () {
console.log(this.$el.clientWidth) // 横幅のピクセル
console.log(this.$el === document.getElementById('app')) // true
}
$el
はルートなDOMを参照するWeb APIです。
生jsのdocument.getElementById
に相当し、等価演算でtrue
を返します。
window.addEventListener
でのイベントリスナはここで定義するといいです。
##beforeUpdate
イベントハンドラ等からメソッドを実行するなどしてデータが変更され、
変更されたデータがDOMに反映される前に呼ばれるフックです。
beforeUpdate () {
console.log(this.appStyle.width) // (10増加して)'130%'
console.log(this.$el.clientWidth) // '120%'分の横幅ピクセル
}
イベントを発火させて横幅のスタイルデータをいじったとしましょう。このとき、スタイルデータこそ更新されましたが、
この時点では変更されたスタイルデータがDOMに反映されていないため、
DOMからは増加する前の横幅が取得されます。
特定のデータの更新をトリガにするならwatcher
を使った方がいいです。
watch: {
'appStyle.width' () {
console.log(this.$el.clientWidth) // '120%'分の横幅ピクセル
}
}
これでwidthだけが更新されると後処理が実行されます。
watcher
も同様に、データがDOMへ反映される前に実行されるので、
beforeUpdate
フックのスコープが小さくなったバージョンと考えてもよさそうです。
##updated
データが変更され、DOMに反映された後に呼ばれるフックです。
updated () {
console.log(this.$el.clientWidth) // '130%'分の横幅ピクセル
}
ここでDOMに反映されます。DOMが更新された後の処理はこのフックで記述します。
こちらも代替として、$nexttick
を使っても同じようにDOM反映後に処理が行えます。
methods: {
extendWidth () {
this.appStyle.width = parseInt(this.appStyle.width) + 10 + '%'
this.$nextTick(function () {
console.log(this.$el.clientWidth) // '130%'分の横幅ピクセル
}
}
##beforeDestroy
vm.$destroy()
がコールされると、Vueインスタンスを破棄します。
その破棄される前に呼ばれるフックです。
<button @click="destroyInstance">destroy</button>
methods: {
destroyInstance () {
this.$destroy()
}
メモリリークの要因ともなるので、役目を終えたインスタンスは破棄していきたいですね。
https://jp.vuejs.org/v2/cookbook/avoiding-memory-leaks.html
##destroyed
vm.$destroy()
がコールされ、Vueインスタンスが破棄された後に呼ばれるフックです。
Vueインスタンスが破棄されると、以下のようになります。
-
watcher
が停止する - イベントリスナが停止する(
v-on
ディレクティブも同様) - 子コンポーネントも同様に影響する