Vue.js Lifecycle Hooks - Complete Explanation π
In Vue.js, lifecycle hooks are special methods that let you execute code at different stages of a Vue instanceβs life. Hereβs an overview of all major lifecycle hooks:
1οΈβ£ Creation Phase (Instance is Created)
1. beforeCreate()
- Called before Vue initializes
data(),computed, ormethods. - You cannot access
this.dataorthis.methodsyet. - Use Case: Logging or setting up non-reactive properties.
beforeCreate() {
console.log("Before Create: ", this.message); // Undefined
}
2. created()
- Called after Vue initializes
data(),computed, andmethods. this.messageis now accessible.- Use Case: Fetching data from APIs, initializing variables.
created() {
console.log("Created: ", this.message); // Now accessible
}
2οΈβ£ Mounting Phase (DOM is Rendered)
3. beforeMount()
- Called before Vue inserts the component into the DOM.
- The template is compiled, but nothing is visible on the screen yet.
- Use Case: Modifying the template before rendering.
beforeMount() {
console.log("Before Mount: ", this.message);
}
4. mounted() (Most Used)
- Called after Vue inserts the component into the DOM.
- Use Case:
- Fetching data from APIs.
- Running animations.
- Setting up event listeners.
mounted() {
console.log("Mounted: ", this.message);
}
β
Example: Fetching data in mounted()
mounted() {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
this.message = data.value;
});
}
3οΈβ£ Updating Phase (Reactivity in Action)
5. beforeUpdate()
- Called before the DOM is updated when data changes.
- Use Case: Perform an action before re-rendering.
beforeUpdate() {
console.log("Before Update: ", this.message);
}
6. updated()
- Called after Vue updates the DOM.
- Use Case:
- Run a function after reactivity changes the DOM.
- Fetch new data based on user input.
updated() {
console.log("Updated: ", this.message);
}
4οΈβ£ Destruction Phase (Instance is Destroyed)
7. beforeDestroy()
- Called before Vue destroys the component.
- Use Case:
- Clean up timers.
- Remove event listeners.
beforeDestroy() {
console.log("Before Destroy: Cleaning up...");
}
8. destroyed()
- Called after Vue removes the component from the DOM.
- Use Case: Debugging after destruction.
destroyed() {
console.log("Component Destroyed.");
}
π― Vue.js Lifecycle Hook Order (Execution Sequence)
1. beforeCreate()
2. created()
3. beforeMount()
4. mounted()
5. beforeUpdate() (Only if data changes)
6. updated() (Only if data changes)
7. beforeDestroy()
8. destroyed()
π Full Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue Lifecycle Hooks</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{ message }}</p>
<button @click="changeMessage">Change Message</button>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
message: "Hello Vue.js"
};
},
beforeCreate() {
console.log("1. Before Create: ", this.message); // undefined
},
created() {
console.log("2. Created: ", this.message); // "Hello Vue.js"
},
beforeMount() {
console.log("3. Before Mount: ", this.message);
},
mounted() {
console.log("4. Mounted: ", this.message);
},
beforeUpdate() {
console.log("5. Before Update: ", this.message);
},
updated() {
console.log("6. Updated: ", this.message);
},
beforeDestroy() {
console.log("7. Before Destroy: Cleaning up...");
},
destroyed() {
console.log("8. Destroyed: Component removed.");
},
methods: {
changeMessage() {
this.message = this.message === "Hello Vue.js" ? "Vue Lifecycle" : "Hello Vue.js";
}
}
});
</script>
</body>
</html>
π― Key Takeaways
- beforeCreate() β created(): Vue initializes data & methods.
- beforeMount() β mounted(): Vue inserts the template into the DOM.
- beforeUpdate() β updated(): Vue updates the DOM when data changes.
- beforeDestroy() β destroyed(): Vue removes the component from the DOM.
π― Vue.js Lifecycle Hooks - Deep Explanation with Real-World Example & Diagrams
Vue.js lifecycle hooks allow you to execute code at different stages of a componentβs life. Let's go step by step, using real-world examples and a diagram to visualize everything.
π 1. Lifecycle Diagram (Execution Flow)
Hereβs how Vue lifecycle hooks execute in order:
Creation Phase:
1. beforeCreate() β Data & methods not available yet
2. created() β Data & methods initialized
Mounting Phase:
3. beforeMount() β Virtual DOM compiled
4. mounted() β DOM elements inserted
Updating Phase:
5. beforeUpdate() β Called before data changes in the DOM
6. updated() β Called after DOM updates
Destroy Phase:
7. beforeDestroy() β Cleanup before removal
8. destroyed() β Component completely removed
πΉ Lifecycle Diagram
This diagram shows how lifecycle hooks interact with the component:
Vue Instance
β¬
+-------------------------+
| beforeCreate() | πΉ Data & methods not available
+-------------------------+
β¬
+-------------------------+
| created() | πΉ Data & methods available
+-------------------------+
β¬
+-------------------------+
| beforeMount() | πΉ Template compiled
+-------------------------+
β¬
+-------------------------+
| mounted() | πΉ DOM is ready
+-------------------------+
β¬
+-------------------------+
| beforeUpdate() | πΉ Called before re-render
+-------------------------+
β¬
+-------------------------+
| updated() | πΉ DOM updated
+-------------------------+
β¬
+-------------------------+
| beforeDestroy() | πΉ Cleanup before removal
+-------------------------+
β¬
+-------------------------+
| destroyed() | πΉ Component removed
+-------------------------+
π 2. Real-World Example
Imagine youβre building an e-commerce product page. You need to:
β Fetch product details from an API when the page loads.
β Show a loading spinner before the data loads.
β Listen for cart updates when the user adds/removes products.
β Remove event listeners when leaving the page.
Hereβs how we apply lifecycle hooks:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue Lifecycle Example</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h1>{{ product.name }}</h1>
<p>{{ product.description }}</p>
<p><strong>Price:</strong> ${{ product.price }}</p>
<button @click="addToCart">Add to Cart</button>
<p v-if="loading">Loading product...</p>
</div>
<script>
new Vue({
el: "#app",
data() {
return {
product: {},
loading: true
};
},
beforeCreate() {
console.log("1οΈβ£ beforeCreate: Data not initialized");
},
created() {
console.log("2οΈβ£ created: Fetching product...");
setTimeout(() => {
this.product = {
name: "Smartphone",
description: "A high-end smartphone with an amazing camera.",
price: 999
};
this.loading = false;
console.log("β
Product fetched");
}, 2000);
},
beforeMount() {
console.log("3οΈβ£ beforeMount: Template is compiled but not inserted into DOM.");
},
mounted() {
console.log("4οΈβ£ mounted: Component is now in the DOM.");
window.addEventListener("resize", this.handleResize);
},
beforeUpdate() {
console.log("5οΈβ£ beforeUpdate: Data is changing...");
},
updated() {
console.log("6οΈβ£ updated: DOM updated with new data.");
},
beforeDestroy() {
console.log("7οΈβ£ beforeDestroy: Cleaning up event listeners...");
window.removeEventListener("resize", this.handleResize);
},
destroyed() {
console.log("8οΈβ£ destroyed: Component removed.");
},
methods: {
addToCart() {
console.log("π¦ Product added to cart!");
},
handleResize() {
console.log("π Window resized!");
}
}
});
</script>
</body>
</html>
π 3. Understanding Execution with Logs
When you open the browser console, this is what youβll see:
1οΈβ£ beforeCreate: Data not initialized
2οΈβ£ created: Fetching product...
3οΈβ£ beforeMount: Template is compiled but not inserted into DOM.
4οΈβ£ mounted: Component is now in the DOM.
β
Product fetched
When you add a product to the cart, the message appears:
π¦ Product added to cart!
When you close the page, Vue cleans up event listeners:
7οΈβ£ beforeDestroy: Cleaning up event listeners...
8οΈβ£ destroyed: Component removed.
π 4. Summary of Lifecycle Hooks
| Hook | When it Runs | Common Use Case |
|---|---|---|
beforeCreate() |
Before Vue initializes data | Logging, non-reactive setup |
created() |
After Vue initializes data | Fetch API, set up variables |
beforeMount() |
Before inserting component in DOM | Modify template before rendering |
mounted() |
After inserting component in DOM | Fetch API, event listeners |
beforeUpdate() |
Before Vue updates the DOM | Debugging before changes |
updated() |
After Vue updates the DOM | Work after reactivity updates |
beforeDestroy() |
Before Vue removes component | Cleanup timers, event listeners |
destroyed() |
After Vue removes component | Final cleanup, debugging |
π 5. When to Use Lifecycle Hooks
| Scenario | Best Lifecycle Hook |
|---|---|
| Fetch data from API | created() or mounted() |
| Modify DOM directly | mounted() |
| Listen for user events | mounted() |
| Cleanup event listeners | beforeDestroy() |
| Debug changes before update | beforeUpdate() |
| Debug after reactivity change | updated() |
π‘ Conclusion
- Lifecycle hooks control different stages of a Vue component.
created()is great for fetching data.mounted()is perfect for event listeners & DOM updates.beforeDestroy()helps clean up unnecessary processes.- Vueβs reactivity system updates the DOM efficiently.
Awesome! Letβs reinforce your understanding with a quick quiz and then dive into a real-world Vue app example using lifecycle hooks. π
π― Quick Vue Lifecycle Quiz
Test yourself with these 5 multiple-choice questions!
Q1: Which lifecycle hook is best for fetching data from an API?
- A)
beforeCreate - B)
created - C)
mounted - D)
beforeDestroy
π Answer: created (B) β
(Data is available, but the DOM isnβt yet mounted. API calls here ensure smooth rendering!)
Q2: Which hook runs when the component is fully inserted into the DOM?
- A)
created - B)
mounted - C)
beforeUpdate - D)
destroyed
π Answer: mounted (B) β
(This is the best place to set up event listeners, access the DOM, or integrate with third-party libraries!)
Q3: When should you remove event listeners like window.addEventListener()?
- A)
beforeCreate - B)
updated - C)
beforeDestroy - D)
mounted
π Answer: beforeDestroy (C) β
(Ensures clean memory usage & prevents errors when switching components!)
Q4: What does beforeUpdate do?
- A) Runs before data changes in Vue
- B) Runs after DOM updates
- C) Runs when the component is removed
- D) Runs before the component is created
π Answer: beforeUpdate (A) β
(Great for debugging before Vue updates the DOM!)
Q5: If a Vue component is removed from the page, which hook runs last?
- A)
beforeDestroy - B)
destroyed - C)
beforeCreate - D)
beforeMount
π Answer: destroyed (B) β
(At this point, Vue has removed everything! You can perform any final cleanup here.)
π₯ Real-World Example: Vue Todo App with Lifecycle Hooks
Letβs build a Vue Todo App that:
β Fetches initial tasks from local storage.
β Auto-saves tasks when updated.
β Cleans up event listeners before closing.
Code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue Todo App</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h1>Todo List</h1>
<input v-model="newTask" @keyup.enter="addTask" placeholder="Add a task">
<button @click="addTask">Add</button>
<ul>
<li v-for="(task, index) in tasks" :key="index">
{{ task }}
<button @click="removeTask(index)">β</button>
</li>
</ul>
</div>
<script>
new Vue({
el: "#app",
data() {
return {
newTask: "",
tasks: []
};
},
beforeCreate() {
console.log("1οΈβ£ beforeCreate: No tasks yet.");
},
created() {
console.log("2οΈβ£ created: Loading tasks...");
const savedTasks = localStorage.getItem("tasks");
if (savedTasks) {
this.tasks = JSON.parse(savedTasks);
}
},
mounted() {
console.log("3οΈβ£ mounted: Todo app is ready.");
window.addEventListener("beforeunload", this.saveTasks);
},
beforeUpdate() {
console.log("4οΈβ£ beforeUpdate: Task list is changing...");
},
updated() {
console.log("5οΈβ£ updated: Task list updated!");
},
beforeDestroy() {
console.log("6οΈβ£ beforeDestroy: Cleaning up...");
window.removeEventListener("beforeunload", this.saveTasks);
},
destroyed() {
console.log("7οΈβ£ destroyed: App removed.");
},
methods: {
addTask() {
if (this.newTask.trim()) {
this.tasks.push(this.newTask.trim());
this.newTask = "";
}
},
removeTask(index) {
this.tasks.splice(index, 1);
},
saveTasks() {
localStorage.setItem("tasks", JSON.stringify(this.tasks));
console.log("π Tasks saved to local storage.");
}
}
});
</script>
</body>
</html>
π Key Takeaways from This Todo App
1οΈβ£ Data Persistence β Saves tasks using localStorage.
2οΈβ£ Auto-Saving β Calls saveTasks() before closing the page.
3οΈβ£ Memory Cleanup β Removes event listeners in beforeDestroy().
Sure! A Student Planner App is a useful alternative to a Todo App. It helps students manage assignments, deadlines, class schedules, and reminders.
π₯ Letβs update our previous example with a Vue.js Student Planner App!
π― Vue Student Planner App
β Features:
β Add assignments with deadlines.
β Sort assignments by due date.
β Persist data using localStorage.
β Show upcoming deadlines in red.
β Remove completed assignments.
π Code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue Student Planner</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<style>
body { font-family: Arial, sans-serif; text-align: center; margin: 20px; }
.deadline-soon { color: red; font-weight: bold; }
</style>
</head>
<body>
<div id="app">
<h1>π Student Planner</h1>
<input v-model="newTask" placeholder="Enter assignment" @keyup.enter="addTask">
<input type="date" v-model="newDeadline">
<button @click="addTask">Add</button>
<ul>
<li v-for="(task, index) in sortedTasks" :key="index">
{{ task.name }} -
<span :class="{ 'deadline-soon': isDeadlineSoon(task.deadline) }">
Due: {{ task.deadline }}
</span>
<button @click="removeTask(index)">β</button>
</li>
</ul>
</div>
<script>
new Vue({
el: "#app",
data() {
return {
newTask: "",
newDeadline: "",
tasks: []
};
},
beforeCreate() {
console.log("1οΈβ£ beforeCreate: No assignments loaded yet.");
},
created() {
console.log("2οΈβ£ created: Loading assignments...");
const savedTasks = localStorage.getItem("tasks");
if (savedTasks) {
this.tasks = JSON.parse(savedTasks);
}
},
mounted() {
console.log("3οΈβ£ mounted: Planner is ready.");
window.addEventListener("beforeunload", this.saveTasks);
},
beforeDestroy() {
console.log("6οΈβ£ beforeDestroy: Cleaning up...");
window.removeEventListener("beforeunload", this.saveTasks);
},
methods: {
addTask() {
if (this.newTask.trim() && this.newDeadline) {
this.tasks.push({ name: this.newTask.trim(), deadline: this.newDeadline });
this.newTask = "";
this.newDeadline = "";
}
},
removeTask(index) {
this.tasks.splice(index, 1);
},
saveTasks() {
localStorage.setItem("tasks", JSON.stringify(this.tasks));
console.log("π Assignments saved.");
},
isDeadlineSoon(deadline) {
const today = new Date();
const dueDate = new Date(deadline);
const diffTime = dueDate - today;
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return diffDays <= 2; // Highlight tasks due in 2 days
}
},
computed: {
sortedTasks() {
return this.tasks.sort((a, b) => new Date(a.deadline) - new Date(b.deadline));
}
}
});
</script>
</body>
</html>
π₯ Key Features of This App
π
Assignments β Add assignments with due dates.
β Deadline Alerts β Upcoming deadlines (within 2 days) turn red.
π Sorting β Tasks auto-sort by due date.
πΎ Persistence β Tasks saved in localStorage.
π Cleanup β Event listeners removed in beforeDestroy().
π Whatβs Next?
Create :
- More student productivity tools (like a GPA Calculator)!
- Vue 3 with Composition API version!
- Enhancements (like notifications)!