Control the flow of time in your components.
1The Component Lifecycle
A component is instantiated, its template is compiled, it is attached to the DOM (mounted), it updates when data changes, and finally, it is destroyed (unmounted). Vue gives you hooks to run code at each of these stages.
2onMounted
onMounted is the most frequently used hook. It runs after the component has been inserted into the DOM. This is the perfect place to fetch data from an API, initialize a 3D canvas, or interact with native DOM elements.
3onUnmounted
onUnmounted runs right before the component is destroyed. It is absolutely critical for performance: you must use it to remove manual window.addEventListener listeners or clear setInterval timers to prevent memory leaks.
4Step-by-Step Breakdown
Every Vue component goes through a lifecycle: It is created, it is mounted to the DOM, it updates when data changes, and it is unmounted when destroyed.
You can hook into these specific moments using Lifecycle Hooks. The most common one is onMounted.
Which lifecycle hook is typically used to fetch initial data from an API because it runs exactly when the component is added to the DOM?
- →onCreated
- →onMounted
- →onUpdated
Why wait for onMounted? Because before onMounted, the HTML elements do not exist yet! If you try to access a DOM element before it mounts, it will be null.
Another important hook is onUnmounted. This runs right before the component is destroyed (e.g., when you navigate to another page).
Which hook should you use to clean up event listeners or setInterval timers so they don't cause memory leaks when the component disappears?
- →onDestroyed
- →onUnmounted
- →onBeforeMount
If you need to know when the DOM updates due to a reactive variable changing, use onUpdated.
Note: In Vue 3 with <script setup>, you do not need onCreated. Any code written directly inside the script block runs during the setup phase (which replaces created).
In Vue 3 with <script setup>, do you need to explicitly use an onCreated hook to run code when the component is initialized?
- →Yes, it is mandatory
- →No, just write code in the script block
Mastering the lifecycle means you never get "Cannot read property of null" errors when accessing the DOM, and you never create memory leaks.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Managing Focus in onMounted
onMounted is the correct hook to call el.focus() on an input the moment a modal opens, since the element is guaranteed to exist in the DOM by then — this is what lets keyboard and screen-reader users land directly on the first interactive field instead of losing their position when a dialog appears.
const inputRef = ref(null);
onMounted(() => inputRef.value?.focus());SEO Implications
- 1
onMounted Never Runs During Server-Side Rendering
onMounted only fires in the browser, by design — Vue's SSR renderer produces the initial HTML string without a real DOM, so any content generated inside onMounted is completely absent from what a crawler receives before JavaScript executes, unlike content computed during setup() itself, which SSR does include.
Best Practices
Pair Every Listener Registered in onMounted with Cleanup in onUnmounted
Any window.addEventListener, setInterval, or third-party subscription started in onMounted must be torn down in the matching onUnmounted call; otherwise it keeps running every time the component is created and destroyed, a classic Vue memory leak.
Frequent Bugs
Accessing a template ref before the component has mounted.
A ref bound to a DOM element via <div ref="boxRef"> is null until after mounting completes. Reading boxRef.value in setup()'s top-level code (outside onMounted) will always be null — move the access inside onMounted(() => { ... }).
Real-World Examples
Real-Time Dashboard Polling
A metrics dashboard starts a setInterval poll in onMounted to refresh data every 5 seconds and explicitly clears it in onUnmounted, so navigating away from the dashboard route stops the network requests instead of leaving a zombie timer running.
let timer;
onMounted(() => {
timer = setInterval(fetchMetrics, 5000);
});
onUnmounted(() => clearInterval(timer));