Lifecycle Hooks

intermediate
12 min

Lifecycle Hooks

Every Vue component goes through a life: it is created, mounted into the DOM, updated as reactive data changes, and eventually unmounted. Lifecycle hooks let you run code at each milestone -- fetching data on mount, cleaning up timers on unmount, measuring the DOM after updates. This lesson maps the lifecycle and shows the hooks you will actually use.

The Lifecycle at a Glance

  1. Setup -- <script setup> runs; reactive state is created. No DOM exists yet.
  2. Mounted -- the component's DOM has been inserted into the page.
  3. Updated -- reactive changes have been re-rendered to the DOM.
  4. Unmounted -- the component has been removed and torn down.

In <script setup>, hooks are functions imported from vue and called with a callback:

vue
<script setup> import { ref, onMounted, onUpdated, onUnmounted } from 'vue' const seconds = ref(0) let timer = null onMounted(() => { timer = setInterval(() => seconds.value++, 1000) console.log('DOM ready:', document.querySelector('.clock')) }) onUpdated(() => { console.log('DOM re-rendered, seconds =', seconds.value) }) onUnmounted(() => { clearInterval(timer) // essential cleanup! }) </script> <template> <p class="clock">Elapsed: {{ seconds }}s</p> </template>

onMounted: Touch the DOM, Start Effects

Until onMounted fires, template refs are null and document queries find nothing from this component. Typical uses:

  • Initializing third-party libraries (charts, maps, editors) that need a real element.
  • Setting focus: combine with a template ref.
  • Starting subscriptions, intervals, or WebSocket connections.
vue
<script setup> import { ref, onMounted } from 'vue' const inputEl = ref(null) // template ref onMounted(() => inputEl.value.focus()) </script> <template> <input ref="inputEl" placeholder="Auto-focused"> </template>

Fetching data

You will often see onMounted(async () => { data.value = await fetchData() }). Note that top-level await-free fetch calls in <script setup> run even earlier -- both are fine for client-side apps; the mounted hook simply guarantees DOM availability, which fetching does not need.

onUnmounted: Always Clean Up

Anything you start, you must stop, or you leak memory and get ghost callbacks firing on dead components:

js
onMounted(() => window.addEventListener('resize', onResize)) onUnmounted(() => window.removeEventListener('resize', onResize))

A tidy pattern is pairing setup and teardown inside one composable (useEventListener) so no component ever forgets the second half.

onUpdated and Friends

onUpdated runs after any reactive change re-renders the DOM -- useful for syncing scroll positions or integrating non-Vue widgets. Do not mutate state inside it or you risk infinite update loops. For most "react to data change" needs, a watch is more precise because it tells you what changed.

The full hook set also includes onBeforeMount, onBeforeUpdate, onBeforeUnmount, and onErrorCaptured (intercept errors from descendants -- great for error boundaries). Two extras, onActivated/onDeactivated, fire for components cached by <KeepAlive>.

Hooks Inside Composables

Because hooks register against the currently initializing component, composables can use them -- this is what makes them so much more powerful than plain utility functions:

js
// composables/useInterval.js import { onMounted, onUnmounted } from 'vue' export function useInterval(fn, ms) { let id = null onMounted(() => (id = setInterval(fn, ms))) onUnmounted(() => clearInterval(id)) }

One rule: hooks must be called synchronously during setup -- never inside setTimeout, awaited code paths, or event handlers.

Key Takeaways

  • Components move through setup → mounted → updated → unmounted; hooks tap each stage.
  • onMounted is where DOM access, template refs, and third-party widgets become safe.
  • Every interval, listener, or subscription started must be cleared in onUnmounted.
  • Prefer watch over onUpdated when you care about a specific piece of data.
  • Composables can register lifecycle hooks, bundling setup and cleanup together.

Next up: Routing with Vue Router -- turning your components into a multi-page single-page application.

Lifecycle Hooks - Vue.js | CodeYourCraft | CodeYourCraft