やくだつブログ

[Vue.js] mixin とコンポーネントのライフサイクルフックはどっちが先に実行されるかな

検証コードを書くまでもなく公式ガイドに答えが載っていました。ミックスインが先だそうです。

オプションのマージ

同じ名前のフック関数はそれら全てが呼び出されるよう配列にマージされます。ミックスインのフックはコンポーネント自身のフック前に呼ばれます。

同期的な処理ならこれで問題ないですが、ミックスインのフックで非同期処理を入れたところ、 await の結果を待たずにコンポーネントの mounted() が呼ばれました。

※下記サンプルは簡略化して別物になっていますが『ミックスインでページ内の全画像の読み込みを待ってからページコンポーネントで個別の処理を開始』ということをしたかった

サンプル

// ミックスイン
export default {
  async mounted() {
    console.log('mixin hook called')
    await this.$_mounted_someMethod()
  },
  methods: {
    // 5秒待ってから resolve() するだけの無意味なメソッド
    $_mounted_someMethod() {
      return new Promise((resolve) => {
        setTimeout(() => {
          console.log('promise resolved')
          resolve()
        }, 5000)
      })
    }
  }
}
// コンポーネント
import mounted from '@/mixins/mounted'

export default {
  mixins: [mounted],
  mounted() {
    console.log('component hook called')
  }
}

『ミックスインのフックが先に呼ばれる』となるとコンソールの表示は mixin hook called → 5秒後に promise resolvedcomponent hook called となりそうですが、実際には mixin hook calledcomponent hook called → 5秒後に promise resolved となります。

ミックスインの非同期処理を待ちたいときはどうすればいいか。

ソリューション

// ミックスイン
export default {
  // mounted は削除してしまう
  // async mounted() {
  //   console.log('mixin hook called')
  //   await this.$_mounted_someMethod()
  // },
  methods: {
    // 5秒待ってから resolve() するだけの無意味なメソッド
    $_mounted_someMethod() {
      return new Promise((resolve) => {
        setTimeout(() => {
          console.log('promise resolved')
          resolve()
        }, 5000)
      })
    }
  }
}
// コンポーネント
import mounted from '@/mixins/mounted'

export default {
  mixins: [mounted],
  async mounted() { // async をつける
    await this.$_mounted_someMethod() // コンポーネントの mounted() にてミックスインのメソッドを呼ぶ
    console.log('component hook called')
  }
}

ミックスインの mounted() で呼んでいたメソッドをコンポーネント側で呼ぶように変更しただけです。

だいたいこんな感じでいいと思いますが、わざわざミックスインでやる必要がないですね。こんな使い方ならばプラグインとして共通化するほうがスマートだと思いました。

戻る