Vue.js Component Lifecycle
Every Vue component goes through a series of stages from birth to removal. These stages are called the component lifecycle. Vue gives you special functions called lifecycle hooks that run automatically at each stage, letting you run code at exactly the right moment.
The Lifecycle — A Diagram Overview
Diagram: Full Component Lifecycle
Component created
│
▼
beforeCreate() ← Runs before data and events are set up
│
▼
created() ← Data is ready. DOM not yet rendered.
│
▼
beforeMount() ← About to insert into the real DOM
│
▼
mounted() ← Component is visible on screen ← Most used hook
│
│ (data changes trigger re-renders)
▼
beforeUpdate() ← Data changed, DOM not updated yet
│
▼
updated() ← DOM updated to match new data
│
│ (component is being removed)
▼
beforeUnmount() ← Component about to be removed
│
▼
unmounted() ← Component fully removed from DOM
beforeCreate
This hook runs before the component initializes its data or events. The data() properties and methods do not exist yet. This hook is rarely used directly in most applications.
Vue.createApp({
beforeCreate() {
console.log("beforeCreate: data is not available yet.");
// this.message → undefined (data not set up)
},
data() {
return { message: "Hello" };
}
}).mount("#app");
created
The created hook runs after Vue sets up data, computed properties, methods, and watchers. The component is not yet visible on the screen, but you can access all reactive data. This is the right place to fetch data from an API when the page loads.
Vue.createApp({
data() {
return { users: [] };
},
created() {
// Data is ready. DOM is not. Good place for API calls.
console.log("created: loading users...");
// fetch("/api/users").then(...)
}
}).mount("#app");
Diagram: created vs mounted for API Calls
created(): ✓ data properties ready ✗ DOM not rendered Best for: starting API calls early mounted(): ✓ data properties ready ✓ DOM is rendered Best for: accessing DOM elements, third-party libraries For most API loading, either works. created() starts the fetch slightly earlier.
beforeMount
This hook runs right before Vue renders the component and inserts it into the DOM. The template is compiled but not yet added to the page. This hook has limited practical use for most developers.
mounted
mounted is the most commonly used lifecycle hook. It runs after Vue finishes rendering the component and inserting it into the real DOM. The component is fully visible to the user.
Use mounted() for:
- Accessing or manipulating DOM elements directly
- Initializing third-party libraries (charts, maps, sliders)
- Setting up timers or intervals
- Subscribing to external data streams
<div id="app">
<canvas id="myChart"></canvas>
<p>Loaded at: {{ loadTime }}</p>
</div>
<script>
Vue.createApp({
data() {
return { loadTime: "" };
},
mounted() {
// DOM is ready — we can access elements
this.loadTime = new Date().toLocaleTimeString();
// Example: initialize a chart library
// const ctx = document.getElementById("myChart");
// new Chart(ctx, { ... });
}
}).mount("#app");
</script>
beforeUpdate and updated
These hooks run whenever the component's reactive data changes and Vue re-renders the DOM.
beforeUpdate()— Data has changed, but the DOM still shows the old values. Useful for capturing the DOM state before a re-render.updated()— DOM is now synchronized with the new data. Avoid modifying data here — it can trigger an infinite update loop.
Vue.createApp({
data() {
return { count: 0 };
},
beforeUpdate() {
console.log("About to update. DOM still shows old count.");
},
updated() {
console.log("DOM updated. New count is now visible.");
},
template: `
<div>
<p>Count: {{ count }}</p>
<button @click="count++">Increment</button>
</div>
`
}).mount("#app");
Diagram: Update Cycle
User clicks "Increment"
│
▼
count changes (count = 1)
│
▼
beforeUpdate() fires ← DOM still shows "Count: 0"
│
▼
Vue re-renders DOM ← DOM now shows "Count: 1"
│
▼
updated() fires ← DOM shows "Count: 1"
beforeUnmount and unmounted
These hooks run when a component is being removed from the page — for example, when a v-if condition becomes false.
beforeUnmount()— Component is about to be removed. The DOM still exists. Clean up here: clear timers, remove event listeners, cancel pending API requests.unmounted()— Component has been fully removed from the DOM.
Vue.createApp({
data() {
return { timerID: null, seconds: 0 };
},
mounted() {
// Start a timer when the component appears
this.timerID = setInterval(() => {
this.seconds++;
}, 1000);
},
beforeUnmount() {
// Stop the timer before the component disappears
clearInterval(this.timerID);
console.log("Timer cleared. Component leaving.");
},
template: `<p>Running for {{ seconds }} seconds.</p>`
}).mount("#app");
Diagram: Why Cleanup Matters
Component mounts → setInterval starts → runs every 1 second Without cleanup: Component removed from DOM setInterval still running in memory → Memory leak → Error when interval tries to update destroyed component With beforeUnmount() cleanup: Component about to be removed clearInterval(this.timerID) → Interval stopped → No memory leak
Lifecycle Hooks in Practice
Practical Use Case: Live Clock
app.component("live-clock", {
data() {
return {
currentTime: "",
intervalID: null
};
},
mounted() {
// Update the time every second
this.updateTime();
this.intervalID = setInterval(this.updateTime, 1000);
},
beforeUnmount() {
// Stop the interval when the clock is removed
clearInterval(this.intervalID);
},
methods: {
updateTime() {
this.currentTime = new Date().toLocaleTimeString();
}
},
template: `<p>Current Time: {{ currentTime }}</p>`
});
Diagram: Clock Lifecycle
Component mounts: updateTime() → currentTime = "10:30:00" setInterval starts → calls updateTime every 1s Every second: updateTime() runs currentTime = "10:30:01", "10:30:02", etc. Vue re-renders the <p> tag Component removed (e.g., user navigates away): beforeUnmount() → clearInterval(this.intervalID) Clock stops. No further DOM updates.
Lifecycle Hook Summary Table
┌──────────────────┬────────────────────────────────────────────┐ │ Hook │ When It Runs / Best Use │ ├──────────────────┼────────────────────────────────────────────┤ │ beforeCreate │ Before data setup. Rarely used. │ │ created │ Data ready, no DOM. Good for early API │ │ │ calls. │ │ beforeMount │ Just before DOM insert. Rarely used. │ │ mounted │ DOM ready. Use for DOM access, libraries, │ │ │ timers, subscriptions. │ │ beforeUpdate │ Data changed, old DOM visible. Capture │ │ │ pre-update state. │ │ updated │ DOM updated. Avoid data changes here. │ │ beforeUnmount │ Before removal. CLEAN UP: timers, │ │ │ listeners, connections. │ │ unmounted │ Component fully removed. │ └──────────────────┴────────────────────────────────────────────┘
Summary
Vue component lifecycle hooks let you run code at specific stages of a component's life. Use created() for early data fetching and mounted() when you need the DOM to exist. The update hooks (beforeUpdate and updated) react to data changes. Always clean up timers, intervals, and event listeners in beforeUnmount() to prevent memory leaks. Understanding the lifecycle helps you write code that runs at exactly the right time and avoids hard-to-find bugs.
