Chapter 35: Vue Lifecycle Hooks
Vue Lifecycle Hooks
These are special functions (or methods) that Vue automatically calls at specific points during a component’s life — from creation → mounting → updating → destruction.
Understanding lifecycle hooks is like knowing when you can safely do certain things:
- Fetch data when component appears on screen
- Set up timers / event listeners when component is ready
- Clean up timers / listeners before component disappears
- React to prop or data changes
- Run code only once when component is first created
In Vue 3 (2026 standard) there are two completely different ways to use lifecycle hooks, depending on whether you use Options API or Composition API (<script setup>).
Both are still very common in 2026 — so you need to know both.
1. Options API – Classic / Legacy Style (still everywhere in old projects)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<script> export default { name: 'MyComponent', // 1. Before anything – almost never used beforeCreate() { console.log('beforeCreate – no reactive data yet') }, // 2. Data & computed are ready, but DOM not yet created() { console.log('created – data ready, good place for initial fetch') this.fetchData() }, // 3. DOM is rendered & mounted to page mounted() { console.log('mounted – DOM is ready, can access this.$refs') this.$refs.myInput.focus() }, // 4. Before update (data changed, before re-render) beforeUpdate() { console.log('beforeUpdate – old DOM still there') }, // 5. After update (re-render finished) updated() { console.log('updated – new DOM is painted') }, // 6. Before unmount (component about to be removed) beforeUnmount() { console.log('beforeUnmount – clean up timers, listeners') clearInterval(this.timer) }, // 7. After unmount (component & DOM gone) unmounted() { console.log('unmounted – component destroyed') } } </script> |
2. Composition API – Modern & Recommended (2026 standard)
In <script setup> we use imported functions from ‘vue’.
These functions are only called once (except onUpdated & onBeforeUpdate).
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
<script setup> import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onErrorCaptured, ref, onServerPrefetch // Nuxt / SSR only } from 'vue' const count = ref(0) // Runs right before mounting (no DOM yet) onBeforeMount(() => { console.log('onBeforeMount – setup finished, but no DOM') }) // Most common – component is mounted & in DOM onMounted(() => { console.log('onMounted – can safely access refs & DOM') // Example: focus input, set up resize listener, fetch data }) // Runs before every re-render (data changed) onBeforeUpdate(() => { console.log('onBeforeUpdate – old DOM still visible') }) // Runs after re-render is complete onUpdated(() => { console.log('onUpdated – new DOM is painted') }) // Runs right before component is destroyed / removed from DOM onBeforeUnmount(() => { console.log('onBeforeUnmount – clean up now!') // Very important: remove event listeners, clear intervals, cancel API requests }) // Runs after component & DOM are completely gone onUnmounted(() => { console.log('onUnmounted – component destroyed') }) // Bonus: error handling (catches errors in child components) onErrorCaptured((err, instance, info) => { console.error('Error in component tree:', err, info) // can return false to stop propagation return false }) </script> |
Real, Practical Example – Timer & Fetch with Proper Cleanup
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
<template> <div class="timer-demo"> <h2>Live Timer + Data Fetch</h2> <p>Seconds since mount: {{ seconds }}</p> <div v-if="loading">Loading user data...</div> <div v-else-if="user"> <p>Welcome back, {{ user.name }}!</p> <p>Last login: {{ user.lastLogin }}</p> </div> <div v-else-if="error">{{ error }}</div> <button @click="seconds = 0">Reset Timer</button> </div> </template> <script setup> import { ref, onMounted, onBeforeUnmount } from 'vue' const seconds = ref(0) const user = ref(null) const loading = ref(true) const error = ref(null) let timer = null onMounted(async () => { console.log('Component mounted – starting timer & fetch') // Start timer timer = setInterval(() => { seconds.value++ }, 1000) // Fetch data try { const response = await fetch('https://jsonplaceholder.typicode.com/users/1') if (!response.ok) throw new Error('Network error') user.value = await response.json() } catch (err) { error.value = err.message } finally { loading.value = false } }) onBeforeUnmount(() => { console.log('Cleaning up before unmount') if (timer) { clearInterval(timer) timer = null } }) </script> <style scoped> .timer-demo { padding: 2rem; text-align: center; } </style> |
Full Lifecycle Order (Vue 3 – 2026)
Parent → Child order matters
- setup() (Composition API) or beforeCreate + created (Options)
- Parent onBeforeMount
- Child onBeforeMount
- Child onMounted
- Parent onMounted
- (Later) Data change → onBeforeUpdate (parent → child) → onUpdated (child → parent)
- When removed → onBeforeUnmount (parent → child) → onUnmounted (child → parent)
Quick Summary Table – When to Use Each Hook (2026 Guide)
| Hook (Composition) | Options API equivalent | Typical Use Cases (2026) | Run Once or Multiple? |
|---|---|---|---|
| onBeforeMount | beforeMount | Rare – prepare before first DOM render | Once |
| onMounted | mounted | Fetch data, set up listeners, focus inputs, init 3rd-party libs | Once |
| onBeforeUpdate | beforeUpdate | Rare – read old DOM before re-render | Multiple |
| onUpdated | updated | DOM-dependent operations after update (rare) | Multiple |
| onBeforeUnmount | beforeUnmount | Clean up: clearInterval, removeEventListener, cancel fetch, dispose libs | Once |
| onUnmounted | unmounted | Final cleanup / analytics (component gone) | Once |
| onErrorCaptured | errorCaptured | Global error boundary for child tree | Multiple |
| onServerPrefetch | — | Nuxt / SSR data fetching before render | Once (SSR only) |
Pro Tips from Real Projects (Hyderabad 2026)
- Most important hooks → onMounted & onBeforeUnmount
- Always clean up in onBeforeUnmount — memory leaks are very common otherwise
- Use nextTick() inside onMounted if you need to wait for child components to mount
- For data fetching → prefer TanStack Query or onServerPrefetch (Nuxt) over raw onMounted
- Don’t fetch in setup() — it’s not reactive-aware & runs on server too
Your mini practice:
- Create component with timer that starts in onMounted
- Clear timer in onBeforeUnmount
- Add fetch call in onMounted with loading/error states
- Add console logs in all hooks to see order
Any part confusing? Want to see:
- Lifecycle with <KeepAlive> (cached components)?
- Lifecycle + async setup / suspense?
- Full auth flow with token refresh in lifecycle?
- Common memory leak examples & how to fix?
Just tell me — we’ll debug and build together step by step 🚀
Happy lifecycle mastering from Hyderabad! 💙
