Every Vue component goes through a series of initialization steps - creating reactive data, compiling the template, mounting to the DOM, updating when data changes, and unmounting. Lifecycle hooks let you run code at specific stages.
| Hook | When it runs | Common use |
|---|---|---|
onBeforeMount | Before component is mounted to DOM | Rarely needed |
onMounted | After component is mounted | Fetch data, access DOM, init libraries |
onBeforeUpdate | Before DOM updates | Access pre-update DOM state |
onUpdated | After DOM updates | Access updated DOM |
onBeforeUnmount | Before component is destroyed | Cleanup (timers, listeners) |
onUnmounted | After component is destroyed | Final cleanup |
onErrorCaptured | When child throws error | Error boundaries |
<template>
<div>
<p>Users: {{ users.length }}</p>
<p>Timer: {{ seconds }}s</p>
<div ref="chartContainer"></div>
</div>
</template>
<script setup>
import {
ref, onBeforeMount, onMounted,
onBeforeUpdate, onUpdated,
onBeforeUnmount, onUnmounted,
onErrorCaptured
} from 'vue'
const users = ref([])
const seconds = ref(0)
const chartContainer = ref(null)
let timer = null
// onBeforeMount - component not yet in DOM
onBeforeMount(() => {
console.log('Before mount - DOM not ready yet')
})
// onMounted - component is in DOM, refs are available
onMounted(async () => {
console.log('Mounted - DOM is ready')
// 1. Fetch initial data
const res = await fetch('/api/users')
users.value = await res.json()
// 2. Access DOM element via ref
console.log('Chart container:', chartContainer.value)
// initChart(chartContainer.value) // init third-party library
// 3. Start timer
timer = setInterval(() => seconds.value++, 1000)
// 4. Add event listener
window.addEventListener('resize', handleResize)
})
// onBeforeUpdate - before DOM re-renders
onBeforeUpdate(() => {
console.log('Before update - old DOM still accessible')
})
// onUpdated - after DOM re-renders
onUpdated(() => {
console.log('Updated - DOM reflects new data')
// Scroll to bottom of list after update
// listEl.value.scrollTop = listEl.value.scrollHeight
})
// onBeforeUnmount - cleanup before destruction
onBeforeUnmount(() => {
console.log('Before unmount - cleanup time')
clearInterval(timer)
window.removeEventListener('resize', handleResize)
})
// onUnmounted - component is gone
onUnmounted(() => {
console.log('Unmounted - component destroyed')
})
// onErrorCaptured - catch errors from child components
onErrorCaptured((error, instance, info) => {
console.error('Child error:', error, info)
return false // prevent error from propagating
})
function handleResize() {
console.log('Window resized:', window.innerWidth)
}
</script>
Understanding Lifecycle Hooks is not just about syntax. In production applications, this topic directly affects maintainability, debugging speed, and team collaboration. Focus on readability, small reusable patterns, and predictable state flow when implementing Lifecycle Hooks.
A practical approach is to first implement the simplest working version, then refactor into reusable pieces (components/composables/stores) only when duplication appears. This helps keep your Vue codebase clean while avoiding over-engineering.
Explore 500+ free tutorials across 20+ languages and frameworks.