Lifecycle Hooks
A component is created, mounted to the DOM, updates as its data changes, and is eventually unmounted. Lifecycle hooks let you run code at these moments — most often to do setup work after mounting (like fetching data) and cleanup before unmounting (like clearing a timer). In the Composition API, these are functions you call inside <script setup>.
onMounted — After the Component Is in the DOM
onMounted registers a callback that runs once, right after the component is inserted into the DOM — the standard place for an initial data fetch, the equivalent of React's useEffect(() => {...}, []) and Angular's ngOnInit. By this point the real DOM exists, so it's also safe to access template elements (via template refs) here. Note you can pass an async function directly — Vue doesn't have React's restriction about effect callbacks not being async.
ngOnInit are distinct), much of Vue's setup just lives at the top level of <script setup> — refs, computeds, and functions declared there run once when the component is created, before it mounts. You only reach for onMounted specifically when you need the DOM to exist first (or want to defer work until after the first render).
onUnmounted — Cleanup Before Removal
onUnmounted runs just before the component is destroyed — the place for cleanup, mirroring React's useEffect cleanup function and Angular's ngOnDestroy. The same universal rule applies: anything that "starts" something ongoing (a timer, an event listener, a subscription) needs a matching "stop" here, or it leaks. A setInterval not cleared in onUnmounted keeps firing after the component is gone.
onUpdated — After a Re-render
onUpdated runs after the component re-renders due to a reactive change and the DOM has been patched. It's used less often than onMounted/onUnmounted — for most "react to a value changing" needs, a watch (Chapter 5) targeting the specific value is cleaner and more precise than this catch-all "something updated" hook.
The Common Pattern — Mount + Cleanup Together
Setup in onMounted paired with matching teardown in onUnmounted is the everyday pattern — adding then removing an event listener, starting then stopping a subscription. In Chapter 10 you'll see how a composable bundles this paired logic into one reusable function, so the mount/unmount pairing lives in one place rather than scattered across every component that needs it — Vue's equivalent of a React custom hook with a cleanup return.
onMounted must be registered synchronously at the top level of <script setup> — not inside an if, a callback, or after an await. This is the same rule-of-hooks constraint as React: Vue needs to associate the hook with the current component instance at setup time, which only works if it's called during the synchronous setup run. Calling onMounted inside an async function after an await, for instance, silently fails to register.
| Vue | React | Angular |
|---|---|---|
| top of <script setup> | component function body | constructor |
| onMounted | useEffect(..., []) | ngOnInit |
| onUpdated | useEffect (no dep array) | ngOnChanges / ngDoCheck |
| onUnmounted | useEffect cleanup | ngOnDestroy |
Coding Challenges
Build a component that fetches a list from any free public API in onMounted and stores it in a ref for display, with a loading state shown until the data arrives.
📄 View solutionBuild a Clock component that starts a setInterval in onMounted (updating a time ref every second) and clears it in onUnmounted. Toggle the component with v-if in a parent to confirm the ticking stops when removed.
📄 View solutionBuild a component that tracks the window's width: add a resize event listener in onMounted (updating a width ref), and remove it in onUnmounted. Display the live width.
📄 View solutionChapter 9 Quick Reference
- Refs/computeds/functions at the top of
<script setup>run at creation, before mount - onMounted — runs once after the component is in the DOM (=
useEffect(.., [])/ngOnInit) - onUnmounted — runs before removal; the place for cleanup (= cleanup fn /
ngOnDestroy) - onUpdated — after a re-render; usually a precise
watchis better - Pair setup in
onMountedwith teardown inonUnmounted(listeners, timers, subscriptions) - Register hooks synchronously in setup — not after an
awaitor inside a conditional - Next chapter: composables — bundling reusable stateful logic (Vue's custom hooks)