codejump

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

Waiting at the end of this page.

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:

JavaScript
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

JavaScript
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.

JavaScript
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:

JavaScript
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 drill

Reading this page is the cheap half. These are the exercises that make you use it.