Back

Vue.jsにおけるライフサイクルフックの理解

Vue.jsにおけるライフサイクルフックの理解

Vueアプリケーションを構築する際、データの取得、リソースのクリーンアップ、DOMとのやり取りをいつ行うべきか悩んでいるなら、ライフサイクルフックを理解する必要があります。これらのフックはVue 3におけるコンポーネント動作の根幹ですが、多くの開発者がどのフックをいつ使用すべきかを理解するのに苦労しています。

本記事では、Composition APIを使用したVue 3のライフサイクルフックについて、コンポーネントの作成から破棄までの各段階を、すぐに適用できる実践的な例とともに解説します。

重要なポイント

  • setupフックは、Vue 2のOptions APIにおけるbeforeCreateとcreatedの両方を置き換えます
  • onMountedは、コンポーネントのレンダリング後のDOM操作やAPI呼び出しに最適です
  • メモリリークを防ぐため、onUnmountedで必ずリソースをクリーンアップしてください
  • ライフサイクルフックは、setup関数内で同期的に呼び出す必要があります

Setupフック:コンポーネントのエントリーポイント

setupフックは、Vue 3 Composition APIの要であり、Vue 2のbeforeCreatecreatedの両方を置き換えます。これはコンポーネントインスタンスが完全に初期化される前に実行されるため、リアクティブな状態を定義し、コンポーネントロジックを構成するのに最適な場所です。

import { ref, reactive } from 'vue'

export default {
  setup(props, context) {
    const count = ref(0)
    const user = reactive({ name: '', email: '' })
    
    // Logic runs immediately, before template compilation
    console.log('Component initializing')
    
    return { count, user }
  }
}

Vue 2のOptions APIとは異なり、setup関数はパラメータとしてpropscontextを受け取るため、thisを使用せずにコンポーネントのプロパティに直接アクセスできます。

マウントフェーズ:onBeforeMount と onMounted

onBeforeMount() - DOM生成前の準備

onBeforeMountフックは、setupの後、コンポーネントのDOMが作成される前に発火します。レンダリング前に実行する必要があるが、DOMアクセスを必要としない操作に使用します。

import { onBeforeMount } from 'vue'

export default {
  setup() {
    onBeforeMount(() => {
      // Initialize non-DOM dependent resources
      console.log('Template compiled, DOM not yet created')
    })
  }
}

onMounted() - DOM準備完了時の操作

onMountedは、DOM関連の初期化の大部分が行われる場所です。コンポーネントのテンプレートがレンダリングされ、ドキュメントに挿入されているため、要素へのアクセスやサードパーティライブラリの初期化を安全に行えます。

import { ref, onMounted } from 'vue'

export default {
  setup() {
    const chartContainer = ref(null)
    
    onMounted(async () => {
      // Fetch data after component mounts
      const data = await fetch('/api/data').then(r => r.json())
      
      // Initialize chart library with DOM element
      // Assuming Chart is imported from a charting library
      new Chart(chartContainer.value, { data })
    })
    
    return { chartContainer }
  }
}

更新フェーズ:リアクティブな状態変更

onBeforeUpdate() - レンダリング前のロジック

リアクティブなデータの変更が再レンダリングをトリガーすると、まずonBeforeUpdateが実行されます。これは、Vueが更新する前に現在のDOM状態を読み取る最後のチャンスです。

import { onBeforeUpdate } from 'vue'

export default {
  setup() {
    onBeforeUpdate(() => {
      // Capture current scroll position before DOM updates
      const scrollY = window.scrollY
      // Store or use scrollY as needed
    })
  }
}

onUpdated() - レンダリング後の操作

VueがDOMを更新した後、onUpdatedが発火します。ここでは注意が必要です。リアクティブな状態を変更すると無限ループを引き起こす可能性があります。

import { onUpdated } from 'vue'

export default {
  setup() {
    onUpdated(() => {
      // DOM has been updated
      // Use nextTick() for specific state change reactions
      console.log('Component re-rendered')
    })
  }
}

アンマウントフェーズ:コンポーネントのクリーンアップ

onBeforeUnmount() - クリーンアップ前のタスク

コンポーネントが削除される前に、onBeforeUnmountは完全に機能するコンポーネントに最後にアクセスする機会を提供します。

import { onBeforeUnmount, reactive } from 'vue'

export default {
  setup() {
    const state = reactive({ data: 'important info' })
    
    onBeforeUnmount(() => {
      // Save component state or notify external systems
      localStorage.setItem('lastState', JSON.stringify(state))
    })
    
    return { state }
  }
}

onUnmounted() - リソースのクリーンアップ

onUnmountedは、メモリリークを防ぐために重要です。ここでイベントリスナー、タイマー、サブスクリプションをクリーンアップします。

import { onMounted, onUnmounted } from 'vue'

export default {
  setup() {
    let timer
    
    const handleResize = () => {
      console.log('Window resized')
    }
    
    onMounted(() => {
      timer = setInterval(() => {
        console.log('Polling...')
      }, 1000)
      
      window.addEventListener('resize', handleResize)
    })
    
    onUnmounted(() => {
      clearInterval(timer)
      window.removeEventListener('resize', handleResize)
    })
  }
}

実践的なパターンとベストプラクティス

Vue 3のライフサイクルメソッドを使用する際は、以下の重要なポイントを覚えておいてください:

  1. フックは必ずインポートしてから使用する(‘vue’から)
  2. フックは同期的に呼び出す—setup()内で、コールバックやPromise内ではなく
  3. Vue 2からVue 3への移行:beforeDestroyonBeforeUnmountに、destroyedonUnmountedになりました
  4. サーバーサイドレンダリング:マウントおよび更新フックはSSR中には実行されません

ライフサイクルフックを持つコンポーネントをテストする場合は、Vue Test Utilsを使用してフックの動作を適切にトリガーおよびアサートしてください。

まとめ

Vue 3のComposition APIライフサイクルフックは、すべての段階でコンポーネントの動作を正確に制御できます。各フックがいつ発火し、どのリソースが利用可能かを理解することで、よりクリーンで高性能なコンポーネントを書くことができます。初期化にはsetup()から始め、DOM操作にはonMounted()を使用し、メモリリークを防ぐためにonUnmounted()で必ずクリーンアップを行いましょう。

よくある質問

はい、1つのsetup関数内で同じライフサイクルフックを複数回呼び出すことができます。Vueは登録された順序で実行します。これは、ライフサイクルフェーズではなく機能ごとにコードを整理するのに便利です。

onMountedはコンポーネントが最初にDOMにレンダリングされた後に1回実行されます。nextTickは次のDOM更新サイクルを待機し、ライフサイクルフック内だけでなく、コード内のどこでも使用できます。特定のリアクティブな変更がDOMに反映されるのを待つ必要がある場合にnextTickを使用してください。

はい、ライフサイクルフックはscript setupで完璧に動作します。setup関数でラップすることなく、インポートして直接呼び出すだけです。script setup構文は自動的にsetupコンテキストを処理します。

エラーハンドリングのために、ライフサイクルフックのロジックをtry-catchブロックでラップします。Vue 3は、子コンポーネントからのエラーをキャッチするためのonErrorCapturedフックも提供しています。グローバルなエラーハンドリングには、Vueアプリケーション作成時にapp.config.errorHandlerを使用してください。

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay