Chapter 102: Vue ‘unmounted’ Lifecycle Hook
Unmounted
(or its modern Composition API name onUnmounted)
This hook is the final goodbye.
When unmounted / onUnmounted runs:
- The component has already been removed from the DOM
- The virtual DOM node no longer exists
- The component instance is dead — most internal references are gone or about to be garbage-collected
- You can no longer safely access$el, template refs, or most DOM-related things
It is not a place for cleanup — cleanup belongs in beforeUnmount / onBeforeUnmount.
unmounted is mainly for:
- Logging / analytics (“this component instance is now dead”)
- Very late, non-DOM-dependent final actions
- Debugging / understanding destruction timing
In 99% of real applications — you don’t need to do anything in onUnmounted.
1. Exact position in the lifecycle (Vue 3 timeline)
Here is the full order with modern names first (Options API names in brackets):
|
0 1 2 3 4 5 6 7 8 9 10 11 |
onBeforeMount (beforeMount) ── about to insert into DOM onMounted (mounted) ── DOM is live onBeforeUpdate (beforeUpdate) ── about to re-render onUpdated (updated) ── DOM patched onBeforeUnmount (beforeUnmount) ── last moment the component is still alive & in DOM onUnmounted (unmounted) ── ← this one – component is removed, instance is dead |
Key timing facts about onUnmounted:
- Runs afteronBeforeUnmount
- Runs after the DOM node has been removed (parentNode.removeChild() has happened)
- Runs before the garbage collector frees the instance (but very soon after)
- Runs only once per component instance (never multiple times)
2. What is available / NOT available in onUnmounted?
This is the critical table — many people get surprised here.
| Feature / Access | Available in onUnmounted()? | Reason / Explanation |
|---|---|---|
| this / component instance | Yes (but dying) | Instance still technically exists, but almost everything is being torn down |
| data() / ref() / reactive() | Yes (but unreliable) | State still exists, but you should not rely on it |
| props | Yes (but unreliable) | Props still there, but parent may already be gone |
| Template refs (ref=”…”) | Usually null | Refs are cleared right before/around unmount — do not rely on them |
| Real DOM / $el | No / null | Element has already been removed from DOM — $el is null or detached |
| DOM APIs (focus, scroll, measure) | No | No DOM element anymore — calling .offsetHeight etc. will error or give 0 |
| Event listeners attached? | Yes (but you should have removed them already) | If you didn’t clean up in onBeforeUnmount → they are now leaked |
| Timers / intervals? | Yes (but you should have cleared them already) | If not cleared → they keep running forever → memory leak |
| Can I emit events? | Technically yes — but pointless | Parent is likely already gone or not listening anymore |
Summary sentence to remember forever:
In onUnmounted / onUnmounted(), the component is already dead — DOM is gone, refs are cleared, instance is about to be garbage-collected. This is not a cleanup hook — cleanup belongs in onBeforeUnmount.
3. Real Example – Logging Destruction + Showing Cleanup Mistake
|
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 |
<template> <div> <h2>unmounted Hook Demo</h2> <button @click="showChild = !showChild"> {{ showChild ? 'Destroy' : 'Create' }} Child Component </button> <ChildComponent v-if="showChild" /> </div> </template> <script setup lang="ts"> import { ref, onMounted, onBeforeUnmount, onUnmounted } from 'vue' const showChild = ref(true) onMounted(() => { console.log('Parent mounted') }) onBeforeUnmount(() => { console.log('Parent beforeUnmount – still alive') }) onUnmounted(() => { console.log('Parent unmounted – I am dead now') }) </script> |
ChildComponent.vue
|
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 |
<template> <div class="child"> <h3>Child Component</h3> <p>I will be destroyed when parent toggles v-if</p> </div> </template> <script setup lang="ts"> import { onBeforeUnmount, onUnmounted } from 'vue' let timer: ReturnType<typeof setInterval> | null = null onBeforeUnmount(() => { console.log('Child beforeUnmount – cleaning up') if (timer) { clearInterval(timer) timer = null console.log('Timer cleared – no leak') } }) onUnmounted(() => { console.log('Child unmounted – instance is gone') // BAD PRACTICE – do NOT do cleanup here // timer may already be gone or in inconsistent state }) </script> <style scoped> .child { padding: 1.5rem; background: #f0f9ff; border-radius: 8px; margin: 1.5rem 0; border: 2px dashed #3b82f6; } </style> |
Console output when you toggle “Destroy” → “Create” multiple times:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Parent mounted Child beforeUnmount – cleaning up Timer cleared – no leak Child unmounted – instance is gone (when you show again) Child beforeUnmount – cleaning up ... |
→ Cleanup must happen in onBeforeUnmount → onUnmounted is too late for reliable cleanup
4. When Do People Actually Use onUnmounted? (Rare but real cases)
In 2026 you will see onUnmounted used for:
- Final logging / analytics “This modal instance was alive for 3 minutes 42 seconds”
- Very late telemetry Sending “component was destroyed” event to analytics (parent may already be gone)
- Debugging / understanding destruction timing Especially in <KeepAlive>, <Transition>, <Suspense> scenarios
- Third-party libraries that require a “destroyed” callback separate from cleanup
Most common answer in interviews / code reviews (2026):
“onUnmounted runs after the component has been removed from the DOM and the instance is being destroyed. Cleanup should be done in onBeforeUnmount. onUnmounted is mostly used for logging, final telemetry, or very late non-DOM-dependent actions.”
Quick Summary Table – beforeUnmount vs unmounted in 2026
| Question | onBeforeUnmount | onUnmounted |
|---|---|---|
| When does it run? | Just before removal from DOM | After removal from DOM, instance is dying |
| DOM / $el / refs available? | Yes | Usually null or detached |
| Safe to cleanup timers/listeners? | Yes – preferred place | Possible but unreliable |
| Safe to read DOM measurements? | Yes | No / risky |
| Can emit events? | Yes | Possible but parent likely gone |
| Most common use | Cleanup (timers, listeners, abort, destroy) | Logging, final analytics, destruction timing |
| Do modern developers use it? | Very often | Rarely |
Pro Tips from Real Projects (Hyderabad 2026)
- Do all cleanup in onBeforeUnmount — timers, listeners, AbortController, .destroy(), etc.
- Use onUnmountedonly for logging, telemetry, or debugging destruction
- Never rely on DOM access in onUnmounted — element is already removed
- In SSR / Nuxt → both hooks run only client-side
- Test cleanup — toggle component 100× with v-if → check memory in DevTools → no leaks
- Combine onMounted + onBeforeUnmount as a pair — init & cleanup always go together
Your mini homework:
- Create a component with timer (setInterval) that logs every second
- Add onBeforeUnmount to clearInterval
- Toggle the component with v-if many times → watch console & CPU/memory
- Move cleanup to onUnmounted → see timer leak (keeps logging after destruction)
Any part confusing? Want full examples for:
- Cleanup patterns (timers, event listeners, AbortController, ResizeObserver)?
- onBeforeUnmount + third-party lib (Chart.js / Mapbox / Swiper) destroy?
- beforeUnmount vs unmounted difference in <KeepAlive> / <Transition>?
- Memory leak demo + how to detect in DevTools?
Just tell me — we’ll trace the lifecycle, create leaks on purpose, and fix them together step by step 🚀
