Lifecycle Hooks in the Composition API
Every Vue component goes through a predictable sequence of phases: it's created, mounted to the DOM, updated in response to reactive changes, and eventually unmounted. The Composition API exposes these phases as importable functions — onMounted, onUpdated, onUnmounted, and others — that register a callback to run at that specific point. This is a direct evolution of the Options API's mounted, updated, and unmounted methods, but as functions they can be called multiple times, imported into composables, and organized by feature rather than by lifecycle stage.
Cricket analogy: A player's day goes through toss, batting, fielding, and end-of-play phases — the Composition API's onMounted/onUpdated/onUnmounted are like being able to call "start batting routine" as a reusable function from any drill, not just a fixed spot in the coach's rulebook.
The core hooks
onMounted fires after the component has been inserted into the DOM — the right place to measure DOM elements, initialize third-party libraries, or start data fetching that depends on rendered elements. onUpdated fires after the DOM has re-rendered due to a reactive data change. onUnmounted fires right before the component instance is destroyed and removed, making it the correct place to clean up timers, event listeners, or subscriptions to avoid memory leaks.
Cricket analogy: onMounted is like a groundskeeper inspecting the pitch only after it's fully rolled and marked — measuring moisture readings that only make sense once the surface exists; onUnmounted is like packing away the covers once play ends for the day.
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const windowWidth = ref(window.innerWidth)
function handleResize() {
windowWidth.value = window.innerWidth
}
onMounted(() => {
window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
})
</script>Other hooks and setup itself
There is no onCreated hook because setup() itself (or the top level of <script setup>) already runs at the point equivalent to the Options API's created hook — any code written there executes before mounting. Additional hooks include onBeforeMount, onBeforeUpdate, onBeforeUnmount, onErrorCaptured (catches errors from descendant components), onActivated/onDeactivated (for components inside <KeepAlive>), and onRenderTracked/onRenderTriggered for debugging reactivity.
Cricket analogy: There's no separate "team selected" hook because the moment the squad sheet is handed in, that's already equivalent to "created" — additional checkpoints like onBeforeMount (warm-up) exist, and onErrorCaptured is like a captain intercepting a fielding mistake before it costs runs, catching it from a junior player.
import { onErrorCaptured } from 'vue'
onErrorCaptured((err, instance, info) => {
console.error('Captured error from child:', err, info)
// return false to stop the error from propagating further
return false
})Hooks inside composables
Because lifecycle hooks are plain function calls rather than component options, they can be called inside a composable function and still correctly attach to whichever component invoked that composable. This is what allows reusable logic like useMousePosition() or useFetch() to register its own onMounted/onUnmounted cleanup, entirely encapsulated away from the consuming component.
Cricket analogy: A reusable "review-drill" routine that any junior player can call still correctly logs onto that specific player's own training record — like a composable's onMounted/onUnmounted attaching to whichever component invoked it, keeping useFetch-style logic encapsulated per user.
In the Options API, mounted, updated, etc. are object properties, so a component can only define each one once. In the Composition API, you can call onMounted multiple times in the same component (or across multiple composables it uses), and all registered callbacks run in the order they were registered.
Lifecycle hook functions like onMounted must be called synchronously during setup() (or the top-level of <script setup>) — calling them inside an async function after an await, or inside a setTimeout, silently fails to register them correctly because Vue relies on tracking the 'currently active component instance' at call time.
- Lifecycle hooks are imported functions (onMounted, onUpdated, onUnmounted, etc.) that register callbacks for specific component life stages.
- onMounted runs after DOM insertion; onUpdated after reactive re-renders; onUnmounted right before teardown for cleanup.
- There is no onCreated hook — setup()/<script setup> top-level code already runs at that point.
- onErrorCaptured lets a component catch errors thrown by descendant components.
- Hooks can be called inside composables, letting reusable logic manage its own mount/unmount behavior transparently.
- Hooks must be registered synchronously during setup — calling them after an await or inside a timeout breaks registration.
Practice what you learned
1. Which hook is the correct place to clean up an event listener registered on window?
2. Why is there no onCreated hook in the Composition API?
3. What is a key difference between Composition API hooks and Options API lifecycle methods?
4. What does onErrorCaptured allow a component to do?
5. Why does calling onMounted() after an await inside an async setup function fail to work correctly?
Was this page helpful?
You May Also Like
The setup() Function and <script setup>
Learn the entry point of the Composition API — the setup() function — and how <script setup> compiles away its boilerplate.
The Vue Instance Lifecycle
An overview of the stages a Vue component instance goes through from creation to unmounting, and the lifecycle hooks available at each stage.
Composables Explained
Understand what composables are, why they replace mixins as Vue's primary reuse pattern, and the conventions they follow.
The Composition API vs Options API
Compares Vue's two component authoring styles, explaining why the Composition API was introduced and when each approach makes sense in real projects.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics