Skip to main content
Vue.js for Beginners to Advanced
CHAPTER 13 Beginner

Vue Lifecycle Hooks

Updated: May 18, 2026
5 min read

# CHAPTER 13

Vue Lifecycle Hooks

1. Chapter Introduction

Every Vue component goes through a lifecycle: it is created, mounted to the DOM, may update when data changes, and eventually unmounted. Lifecycle hooks let you run code at specific phases — fetching data when mounted, cleaning up timers before unmounting.

2. Learning Objectives

  • Understand the complete Vue 3 component lifecycle.
  • Use onMounted for DOM operations and data fetching.
  • Use onUpdated for post-update DOM reads.
  • Use onUnmounted for cleanup.
  • Use onBeforeMount and other pre-hooks.

3. Lifecycle Flow Diagram

text
123456789101112131415161718192021222324252627282930313233343536
Component Lifecycle:

                createApp().mount()
                      │
              ┌───────▼────────┐
              │ setup() runs   │ ← onBeforeCreate (Options API only)
              │ refs created   │ ← onCreated (Options API only)
              └───────┬────────┘
                      │
              ┌───────▼────────┐
              │ onBeforeMount  │ ← Template compiled, not yet in DOM
              └───────┬────────┘
                      │
              ┌───────▼────────┐
              │  onMounted     │ ← Component in DOM ✅ Fetch data here!
              └───────┬────────┘
                      │
              [Data Changes?]
                      │
              ┌───────▼────────┐
              │ onBeforeUpdate │ ← Before DOM patches
              └───────┬────────┘
                      │
              ┌───────▼────────┐
              │   onUpdated    │ ← After DOM patches
              └───────┬────────┘
                      │
              [Component removed?]
                      │
              ┌───────▼────────┐
              │ onBeforeUnmount│ ← Component still accessible
              └───────┬────────┘
                      │
              ┌───────▼────────┐
              │  onUnmounted   │ ← Cleanup: timers, listeners ✅
              └────────────────┘

4. Lifecycle Hooks Code

vue
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
<script setup>
import {
  ref,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onErrorCaptured,
  onActivated,
  onDeactivated
} from &#039;vue'

const count = ref(0)
const users = ref([])
const loading = ref(false)
let timer = null

// onBeforeMount: Called before component is mounted to DOM
// DOM not accessible yet
onBeforeMount(() => {
  console.log(&#039;Before mount — DOM not ready yet')
})

// onMounted: Called after component is mounted to DOM
// ✅ Best place for: API calls, DOM manipulation, 3rd party library init
onMounted(async () => {
  console.log(&#039;Component mounted — DOM ready!')

  // ✅ Fetch initial data
  loading.value = true
  try {
    const response = await fetch(&#039;https://jsonplaceholder.typicode.com/users?_limit=3')
    users.value = await response.json()
  } finally {
    loading.value = false
  }

  // ✅ Start intervals, subscriptions
  timer = setInterval(() => count.value++, 1000)

  // ✅ Access DOM elements
  const el = document.querySelector(&#039;#my-element')
  if (el) el.focus()
})

// onBeforeUpdate: Reactive data changed, DOM not yet updated
onBeforeUpdate(() => {
  console.log(&#039;Data changed — about to patch DOM')
})

// onUpdated: DOM has been updated
// ✅ Access updated DOM (but don't mutate state here — infinite loop!)
onUpdated(() => {
  console.log(&#039;DOM patched — count is now:', count.value)
})

// onBeforeUnmount: Component about to be removed
onBeforeUnmount(() => {
  console.log(&#039;About to unmount — save state, pause timers')
})

// onUnmounted: Component removed from DOM
// ✅ ALWAYS clean up here!
onUnmounted(() => {
  console.log(&#039;Component unmounted')
  clearInterval(timer)                     // Clear timer
  window.removeEventListener(&#039;resize', onResize)  // Remove listeners
})

// onErrorCaptured: Catch errors from child components
onErrorCaptured((err, component, info) => {
  console.error(&#039;Error caught:', err, info)
  return false  // Prevent propagation
})

// onActivated/onDeactivated: For <KeepAlive> wrapped components
onActivated(() => console.log(&#039;Component activated from cache'))
onDeactivated(() => console.log(&#039;Component deactivated to cache'))

function onResize() { console.log(&#039;Window resized') }
</script>

<template>
  <div>
    <div v-if="loading">Loading users...</div>
    <ul v-else>
      <li v-for="user in users" :key="user.id">{{ user.name }}</li>
    </ul>
    <p>Timer: {{ count }}s</p>
  </div>
</template>

5. Practical Patterns

vue
1234567891011121314151617181920212223242526272829303132333435363738
<script setup>
import { ref, onMounted, onUnmounted } from &#039;vue'

// Pattern 1: Cleanup subscription
const mouseX = ref(0)
const mouseY = ref(0)

function trackMouse(e) {
  mouseX.value = e.clientX
  mouseY.value = e.clientY
}

onMounted(() => {
  window.addEventListener(&#039;mousemove', trackMouse)
})
onUnmounted(() => {
  window.removeEventListener(&#039;mousemove', trackMouse)
})

// Pattern 2: Third-party library
import { ref, onMounted, onUnmounted } from &#039;vue'

const chartEl = ref(null)  // Template ref
let chart = null

onMounted(() => {
  // Initialize Chart.js or any library
  // chart = new Chart(chartEl.value, { ... })
})
onUnmounted(() => {
  // chart?.destroy()
})
</script>

<template>
  <p>Mouse: {{ mouseX }}, {{ mouseY }}</p>
  <canvas ref="chartEl"></canvas>
</template>

6. Common Mistakes

  • Fetching data in setup() directly (synchronously): Data fetching is async. Always use onMounted with async/await for initial data fetches.
  • Mutating state in onUpdated: This creates an infinite loop — update → onUpdated → update → onUpdated. Read DOM in onUpdated, don't write state.

7. MCQs

Question 1

Best lifecycle hook for API calls on load?

Question 2

onUnmounted is used for?

Question 3

onUpdated fires when?

Question 4

Is the DOM accessible in setup()?

Question 5

onBeforeUnmount vs onUnmounted?

Question 6

onActivated is for?

Question 7

onErrorCaptured catches errors from?

Question 8

What does return false in onErrorCaptured do?

Question 9

Template refs are accessible in?

Question 10

Infinite loop risk exists in?

8. Interview Questions

  • Q: Why should you clean up event listeners and timers in onUnmounted?
  • Q: What is the difference between onMounted and onBeforeMount?

9. Summary

Vue 3's lifecycle hooks provide precise control over each phase of a component's life. onMounted is the most important — it's where data fetching and DOM initialization belong. onUnmounted is equally important — every resource acquired in onMounted should be released in onUnmounted to prevent memory leaks.

10. Next Chapter Recommendation

In Chapter 14: Vue Router Basics, we add client-side navigation to Vue applications — defining routes, linking pages, and building a multi-page SPA.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·