AcademyVue
Lifecycle Hooks
Every lifecycle hook that sets something up has a matching one that tears it down — onMounted without onUnmounted is a leak waiting to happen.
2 min readUpdated 3 exercises
A component moves through the same stages every time
Every component instance is created, mounted to the DOM, updated some number of times as its reactive state changes, and eventually unmounted. Composition API hooks let code run at each of those specific moments:
import { onMounted, onUpdated, onUnmounted } from 'vue'
onMounted(() => { /* the DOM now exists */ })
onUpdated(() => { /* the DOM was just patched for a reactive change */ })
onUnmounted(() => { /* the component is gone; clean up */ })onMounted is the one reached for constantly — anything that needs the real DOM (focusing an input, measuring an element, initializing a third-party library that expects a DOM node) has to wait for it, the same reasoning behind why template refs start null.
Anything wired up in onMounted is that component's own responsibility to tear down
onMounted(() => {
window.addEventListener('resize', handleResize)
})
// No onUnmounted — the listener, and whatever closure it captured, outlive
// the component. Every mount leaks one more listener that never goes away.Global listeners, intervals, subscriptions, WebSocket connections — anything that reaches outside the component's own DOM subtree needs a matching onUnmounted that undoes exactly what onMounted did. This is not automatic: Vue tears down the component's own DOM and reactive effects on unmount, but it has no way to know about a window-level listener your code attached by hand.
function handleResize() { /* ... */ }
onMounted(() => window.addEventListener('resize', handleResize))
onUnmounted(() => window.removeEventListener('resize', handleResize))removeEventListener needs the exact same function reference addEventListener was given — an inline arrow function passed directly to addEventListener can never be removed later, because there is no way to refer back to it. This is why handleResize is declared once, by name, and referenced from both hooks.
The pattern generalizes to composables
A composable that starts something in onMounted follows the same rule — it just means the composable itself calls both hooks internally, so every component that uses it gets the cleanup for free without writing it out:
function useWindowWidth() {
const width = ref(window.innerWidth)
function update() { width.value = window.innerWidth }
onMounted(() => window.addEventListener('resize', update))
onUnmounted(() => window.removeEventListener('resize', update))
return width
}What interviewers check
Whether onMounted alone raises a "what about cleanup?" question unprompted — the pairing is the whole point, and a candidate who reaches for onMounted without even considering onUnmounted is the same gap as forgetting a cleanup function in a React effect.
Now practice it
2 quizzes · 1 drillReading this page is the cheap half. These are the exercises that make you use it.
- Lifecycle HooksProA resize listener wired up in onMounted with no onUnmounted — a shared counter proves the leak directly.DrillSolve · MediumDrillSolve · Medium
- Options API · Advanced PatternsAdvanced-tier Vue Fundamentals questions that assume the full lifecycle, not just onMounted, is already familiar.QuizTake · HardQuizTake · Hard
- Composition API · Advanced ComposablesLifecycle timing interacts with refs, watchers and composables in ways this harder question set exercises directly.QuizTake · HardQuizTake · Hard
Read next
Template Refs: Reaching the Real DOM
A template ref is null until onMounted — the component has to exist in the DOM before anything can point at it.
2 min
Custom Directives
A directive is the same mounted/unmounted lifecycle a component has, applied to a raw DOM element instead of a component instance.
2 min