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 分類で把握すると良い。
- 初回セットアップ後にやる処理 →
onMounted - 更新後にやる処理 →
onUpdated - 破棄時に後始末する処理 →
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 から外されること |
| cleanup | timer や listener など副作用の後始末 |
| synchronous registration | setup の同期的な実行中に hook を登録すること |
| watcher | 特定 state の変化を監視する仕組み。lifecycle hook とは役割が異なる |