Lifecycle Hooks - コンポーネントの時間軸と副作用配置

ロードマップ: Vue.js学習ロードマップ

公式ドキュメント: https://vuejs.org/guide/essentials/lifecycle.html

公式ダイアグラム: https://vuejs.org/guide/essentials/lifecycle.html#lifecycle-diagram

What(何についてか)

Vue コンポーネントは、生成, 初回描画, 更新, 破棄という時間軸を持つ。 Lifecycle Hooks は、その各段階に応じてユーザーコードを差し込む仕組みである。 この章では、Composition API における onMounted, onUpdated, onUnmounted を中心に、hook の登録タイミングと副作用の置き場所を整理する。

Why(なぜ必要か)

すべての処理をコンポーネント定義直後に実行できるわけではない。 DOM が生成されてからでないと意味がない処理、再描画後でないと成立しない処理、破棄時に掃除しなければならない処理がある。 Lifecycle Hooks を使うことで、コンポーネントの段階に応じて適切なタイミングに処理を配置できる。

How(どう動くか)

1. コンポーネントは時間軸を持つ

Vue コンポーネントは概念的に次の流れをたどる。

作成開始

状態やリアクティビティの準備

テンプレート評価と初回描画

DOM へ mount

状態変更に応じて更新

不要になれば unmount

この時系列に対して、Lifecycle Hooks が差し込まれる。

2. Composition API では hook 関数を登録する

<script setup>
import { onMounted } from 'vue'
 
onMounted(() => {
  console.log('the component is now mounted.')
})
</script>

Options API では mounted() のように宣言していたが、Composition API では onMounted() のような関数を使う。 Koei の学習方針では Composition API を正とし、<script setup> で hook を登録する理解が中心になる。

3. よく使う hook は 3 つある

onMounted

初回描画が終わり、DOM ノードが作られた後に実行される。 DOM 要素へのアクセスや初回副作用に向く。

主な用途:

  • input にフォーカスを当てる
  • DOM サイズを測定する
  • 外部ライブラリを初期化する
  • 初回データ取得を開始する

onUpdated

状態変更によって DOM が再描画された後に実行される。 更新後の DOM に依存する処理に向く。

ただし、再描画のたびに走りうるため乱用は避ける。 値変化への反応が主目的なら watcher の方が自然なことが多い。

onUnmounted

コンポーネントが破棄される時に実行される。 副作用の後始末を行う場所である。

主な用途:

  • timer の解除
  • event listener の解除
  • subscription の停止
  • 外部インスタンスの破棄

4. hook は setup の同期的な流れで登録する必要がある

Vue は hook を「現在アクティブなコンポーネントインスタンス」に紐づける。 そのため、hook 登録は setup の同期的な実行中に行う必要がある。

setTimeout(() => {
  onMounted(() => {
    // this won't work.
  })
}, 100)

このような非同期遅延後の hook 登録は、どのコンポーネントに属するかを Vue が正しく関連付けられないため機能しない。

5. hook は「コンポーネントの段階」に反応する

Lifecycle Hooks は値の変化監視とは役割が違う。

  • コンポーネントが mount された後に 1 回だけやりたい → onMounted
  • コンポーネントが消える時に掃除したい → onUnmounted
  • 特定の状態変化に反応したい → watch / watchEffect を検討する

したがって、Lifecycle Hooks は「値が変わったら」ではなく「コンポーネントの時間軸上のどの地点か」を基準に使う。

Lifecycle の整理図

flowchart LR
  A["コンポーネント生成開始"] --> B["状態・リアクティビティ準備"]
  B --> C["初回描画"]
  C --> D["DOM mount"]
  D --> E["onMounted"]
  E --> F["状態変更"]
  F --> G["DOM update"]
  G --> H["onUpdated"]
  H --> I["不要になれば unmount"]
  I --> J["onUnmounted"]

公式ダイアグラムをどう読むか

公式の Lifecycle Diagram は、コンポーネント生成から破棄までの内部工程をより細かく示した参照図である。 この段階では細部を暗記する必要はなく、まずは次の 3 分類で把握すると良い。

  1. 初回セットアップ後にやる処理 → onMounted
  2. 更新後にやる処理 → onUpdated
  3. 破棄時に後始末する処理 → onUnmounted

実務での判断軸

DOM が必要な初回処理

<script setup>
import { onMounted } from 'vue'
 
onMounted(() => {
  // focus, size measurement, library init
})
</script>

後始末が必要な副作用

<script setup>
import { onMounted, onUnmounted } from 'vue'
 
let timerId
 
onMounted(() => {
  timerId = window.setInterval(() => {
    // polling
  }, 1000)
})
 
onUnmounted(() => {
  clearInterval(timerId)
})
</script>

値変化への反応は watcher を優先検討

onUpdated に何でも置くのではなく、特定 state の変化に反応したい場合は watch 系 API の方が意図に合う。

Options API → Composition API 差分(補足)

項目Options API(旧)Composition API(新)
hook の宣言mounted(), updated(), unmounted()onMounted(), onUpdated(), onUnmounted()
this 依存component instance の this を使う文化がある<script setup> では this を使わず、変数と関数を直接参照する
登録方法options object に書くsetup 実行中に同期的に関数登録する
学習上の重心インスタンスメソッド的発想副作用をどの時点に置くかという時間軸の発想

Key Concepts

用語説明
lifecycleコンポーネントの生成, 描画, 更新, 破棄の時間軸
lifecycle hookその特定段階で実行されるユーザーコード
onMounted初回描画後、DOM が使える段階で実行される hook
onUpdated更新後 DOM に対して実行される hook
onUnmounted破棄時の後始末に使う hook
mountコンポーネントが DOM に接続されること
unmountコンポーネントが DOM から外されること
cleanuptimer や listener など副作用の後始末
synchronous registrationsetup の同期的な実行中に hook を登録すること
watcher特定 state の変化を監視する仕組み。lifecycle hook とは役割が異なる