Vueのライフサイクル

## 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では、いくつかフックが用意されている。

## コンポーネント

説明にあたって以下のようなコンポーネントを想定する。
概要は、スタイルデータを用意し、横幅が拡大するボタンを設置しただけのコード。
フック等は適宜示すので省略してます。

```vuejs:app.vue
<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プロパティ等を参照しても何もありません。

```js

beforeCreate: {
  console.log(this.appStyle.width) // 'undefined'
  this.extendWidth // "this.extendWidth is not a function"
}
```

## created

Vueインスタンスを生成し、データが初期化がされた後に一度だけ呼ばれるフックです。
ここでリアクティブデータやメソッド等を参照できます。

```js

created: {
  console.log(this.appStyle.width) // '120%'
  // this.extendWidth // Methods are also accessible
}
```

`axios`を利用してAPIからデータを取得するタイミングはここがいいです。

## beforeMount

VueインスタンスがDOMにマウントされる前に一度だけ呼ばれるフックです。
この時点までのライフサイクルでは、DOMの操作を行うことはできません。

```js
beforeMount () {
  // Error
  console.log(this.$el.clientWidth)
},
```

## mounted

VueインスタンスがDOMにマウントされた後に一度だけ呼ばれるフックです。
ここでDOMにアクセスできます。

```js
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に反映される前に呼ばれるフックです。

```js
beforeUpdate () {
  console.log(this.appStyle.width) // (10増加して)'130%'
  console.log(this.$el.clientWidth) // '1２0%'分の横幅ピクセル
}
```

イベントを発火させて横幅のスタイルデータをいじったとしましょう。このとき、スタイルデータこそ更新されましたが、
この時点では変更されたスタイルデータがDOMに反映されていないため、
DOMからは増加する前の横幅が取得されます。

特定のデータの更新をトリガにするなら`watcher`を使った方がいいです。

```js
watch: {
  'appStyle.width' () {
    console.log(this.$el.clientWidth) // '1２0%'分の横幅ピクセル
  }
}
```

これでwidthだけが更新されると後処理が実行されます。

`watcher`も同様に、データがDOMへ反映される前に実行されるので、
`beforeUpdate`フックのスコープが小さくなったバージョンと考えてもよさそうです。

##updated

データが変更され、DOMに反映された後に呼ばれるフックです。

```js
updated () {
  console.log(this.$el.clientWidth) // '130%'分の横幅ピクセル
}
```

ここでDOMに反映されます。DOMが更新された後の処理はこのフックで記述します。

こちらも代替として、`$nexttick`を使っても同じようにDOM反映後に処理が行えます。

```js
methods: {
  extendWidth () {
    this.appStyle.width = parseInt(this.appStyle.width) + 10 + '%'
    this.$nextTick(function () {
      console.log(this.$el.clientWidth) // '130%'分の横幅ピクセル
    }
  }
```

##beforeDestroy
`vm.$destroy()`がコールされると、Vueインスタンスを破棄します。
その破棄される前に呼ばれるフックです。

```vuejs
<button @click="destroyInstance">destroy</button>
```

```js
methods: {
  destroyInstance () {
    this.$destroy()
  }
```

メモリリークの要因ともなるので、役目を終えたインスタンスは破棄していきたいですね。
https://jp.vuejs.org/v2/cookbook/avoiding-memory-leaks.html


##destroyed
`vm.$destroy()`がコールされ、Vueインスタンスが破棄された後に呼ばれるフックです。
Vueインスタンスが破棄されると、以下のようになります。

- `watcher`が停止する
- イベントリスナが停止する(`v-on`ディレクティブも同様)
- 子コンポーネントも同様に影響する