Unlocking the mystery of vue.js lifecycle hooks

Zipy
ZipyAI
Published in
11 min readJul 20, 2023

— by Anom Warbhuvan

As a vue js developer, you know how enjoyable and simple it is to create lively and interactive user interfaces with this amazing framework. You can use expressive templates, reactive data, and component composition to build awesome web apps. But, there is always a question among developers i.e which one to choose: vue js or react? Both these frameworks have their pros and cons and those works well in suitable project as per your needs.

For any framework, there is always behind the scene queries such as how does Vue know when to render, update, or destroy your component? How can you tap into these processes and tailor them to your specific requirements? That’s where lifecycle hooks come in.

Like React Lifecycle hooks, vue js hooks also let you hook into the various stages of your component’s lifecycle. These lifecycle methods enable developers to execute actions before, during, and after creation, mounting, updating, or destruction of their components.

In this blog post we will explore the various vue js lifecycle hooks and discuss their effective utilization. Additionally we will present numerous scenarios and examples that cover the practical application of these hooks. We will also cover vue js lifecycle hook errors and vue js error monitoring.

Now, let’s dive into it.

What are lifecycle hooks?

During the lifecycle of a vue component, functions called lifecycle hooks are invoked at specific stages. Every vue instance goes through an initialization process when it is created — for example, it must set up the database, populate the model, bind the instance to the DOM, and update the DOM when the data changes.

Similarly, React components also have a lifecycle that consists of different phases, such as mounting, updating, and unmounting. Here, the useEffect hook for react lifecycle allows you to perform side effects or run custom logic in response to changes in props, state, or context.

Why are vue js lifecycle hooks important

Lifecycle hooks are important in vue js because they provide a window into how the library works behind the scenes. They notify you when elements are created, added to the DOM, modified or destroyed. Having a good understanding of when objects are created, set, updated, and destroyed is essential to understanding library reactivity.

Understanding the Vue.js component lifecycle

Overview of the component lifecycle stages

The vue component lifecycle are the steps a component goes through from creation to destruction. These phases include initialization, sample collection, setup, update, and disposal. At all levels, vue js provides lifecycle hooks, that developers can use to customize actions or execute code.

The significance of each stage in the lifecycle

Each stage in the vue js component lifecycle has its own significance. For example, during the initialization stage, the component sets up data observation and compiles the template. During the mounting stage, the instance is mounted to the DOM and the initial rendering takes place. During the updating stage, the DOM is updated when data changes. Finally, during the destruction stage, the component is destroyed and any necessary cleanup takes place.

Different hooks in component lifecycle

beforeCreate and created hooks

The beforeCreate and created hooks are the first ones to be executed in your component. They allow you to set things up in your component, both during client rendering and server rendering. Unlike any of the other hooks, these hooks are also run during server-side rendering.

In simple terms, the beforeCreate hook runs when the context is fired — data is not yet heard, events are not yet set. You can use this hook to perform some initial configuration or logic that does not depend on reactive data or events.

The created hook runs after the data and events have been set up, but before the template and virtual DOM have been mounted or rendered. You can use this hook to access reactive data and events, make API calls, or perform other operations that need access to this context.

Here is an example of using these hooks:

export default {
data() {
return {
message: "Hello Vue!"
};
},
beforeCreate() {
console.log("beforeCreate hook");
console.log(this.message); // undefined
},
created() {
console.log("created hook");
console.log(this.message); // Hello Vue!
this.fetchData(); // API call
},
methods: {
fetchData() {
// some logic to fetch data from an endpoint
}
}
};

In this example, we define a data property called message, and two hooks: beforeCreate and created. In the beforeCreate hook, we log a message to the console, and try to access this.message, which is undefined at this point. In the created hook, we log another message to the console, and access this.message, which is now reactive and has the value “Hello Vue!”. We also call a method called fetchData, which performs an API call to fetch some data from an endpoint.

beforeMount and mounted hooks

The beforeMount and mounted hooks are often the most used hooks. They allow you to access your component immediately before and after the first render. They do not, however, run during server-side rendering.

The beforeMount hook runs before the template and virtual DOM have been mounted or rendered - you can use this hook to perform some logic that needs to run before the initial rendering.

The mounted hook runs after the template and virtual DOM have been mounted or rendered - you can use this hook to access or modify the DOM of your component, set up event listeners, or perform other operations that need access to this.$el. Here, this.$el is a property of a vue instance or component that refers to the HTML element that the instance or component is mounted.

Here is an example of using these hooks:

<template>
<div ref="example-element">{{ message }}</div>
</template>

<script>
export default {
data() {
return {
message: "Hello Vue!"
};
},
beforeMount() {
console.log("beforeMount hook");
// access the element via template ref
console.log(this.$refs["example-element"]); // undefined
},
mounted() {
console.log("mounted hook");
// access the element via template ref
console.log(this.$refs["example-element"]); // <div>Hello Vue!</div>
}
};
</script>

In this example, we define a data property called message, and two hooks: beforeMount and mounted. We also use a template ref to access a div element in the template. In the beforeMount hook, we log a message to the console, and try to access the div element via this.$refs[“example-element”], which is undefined at this point.

In the mounted hook, we log another message to the console, and access the div element via this.$refs[“example-element”], which is now available and has the text content “Hello Vue!”.

beforeUpdate and updated hooks

The beforeUpdate and updated hooks are triggered when data changes on your component and the update cycle starts, just before and after the DOM is changed and shown again. They let you do things before and after your component has been updated.

The beforeUpdate hook runs when data changes on your component and the update cycle starts, just before the DOM is changed and shown again. You can use this hook to get the new state of any changing data on your component before it gets rendered, or to do some logic that depends on the data changes.

The updated hook runs when data changes on your component and the DOM has been changed and shown again. You can use this hook to access or change the DOM of your component, or to do some things that need this.$el after it has been changed.

Here is an example of using the beforeUpdate hook to compare the old and new values of a prop:

<template>
<div>
<p>{{ counter }}</p>
<button @click="increment">Increment</button>
</div>
</template>

<script>
export default {
data() {
return {
counter: 0
};
},
beforeUpdate() {
console.log("beforeUpdate hook");
console.log(this.counter); // old value
},
updated() {
console.log("updated hook");
console.log(this.counter); // new value
this.$nextTick(() => {
// access the updated DOM
console.log(this.$el.querySelector("p").textContent);
});
},
methods: {
increment() {
this.counter++;
}
}
};
</script>

In this example, we define a data property called counter, and two hooks: beforeUpdate and updated. We also have a button that increments the counter when clicked. In the beforeUpdate hook, we write a message and the old value of this.counter on the console.

In the updated hook, we log another message to the console, and the new value of this.counter. We also use this.$nextTick to access the updated DOM, and log the text content of the ‘p’ element.

When the button is clicked once the output displayed in the console will be as follows:

beforeUpdate hook
0
updated hook
1
1

We can see that the beforeUpdate hook runs before the counter is incremented, and the updated hook runs after the counter is incremented and the DOM is updated.

beforeDestroy and destroyed hooks

The beforeDestroy and destroyed hooks are triggered when your component is about to be destroyed or removed from the DOM. They allow you to perform actions before and after your component has been destroyed.

The beforeDestroy hook runs before your component is destroyed - you can use this hook to perform some cleanup tasks or resource management, such as removing event listeners, timers, subscriptions, etc.

The destroyed hook runs when your component is no more - you can use this hook to do some things at the end that need this, such as logging or talking to other components.

Here is an example of using the beforeDestroy hook to remove an event listener:

<template>
<div>
<p>{{ message }}</p>
<button @click="destroy">Destroy</button>
</div>
</template>

<script>
export default {
data() {
return {
message: "Hello Vue!"
};
},
beforeDestroy() {
console.log("beforeDestroy hook");
// perform some cleanup tasks
clearInterval(this.timer);
},
destroyed() {
console.log("destroyed hook");
// perform some final operations
this.notify("Component destroyed");
},
created() {
// set up a timer
this.timer = setInterval(() => {
this.message = new Date().toLocaleTimeString();
}, 1000);
},
methods: {
destroy() {
// manually destroy the component
this.$destroy();
},
notify(message) {
// some logic to notify other components
alert(message);
}
}
};
</script>

In this example, we define a data property called message, and two hooks: beforeDestroy and destroyed. We also have a button that manually destroys the component when clicked. In the created hook, we set up a timer that updates the message with the current time every second. In the beforeDestroy hook, we clear the timer to avoid memory leaks. In the destroyed hook, we call a method called notify that alerts a message to other components.

If we click the button once, we will see an alert saying “Component destroyed”, and then the following output in the console:

We can see that the beforeDestroy hook runs before the component is destroyed, and the destroyed hook runs after the component is destroyed.

Vue 3 Composition API and lifecycle hooks

Vue 3 introduced a new way of writing components called the Composition API. The Composition API is an alternative to the Options API that allows you to use reactive state, computed properties, methods, watchers, and lifecycle hooks inside a single setup function. The Composition API also provides better TypeScript support, code reuse, and composition.

The Composition API affects the usage of lifecycle hooks in vue 3 in two ways:

  • You need to import the lifecycle hooks from vue instead of using them as options in your component.
  • You need to call the lifecycle hooks inside the setup function instead of outside it.

Here is an example of using the Composition API and lifecycle hooks in vue 3:

<template>
<div>
<p>{{ message }}</p>
<button @click="increment">Increment</button>
</div>
</template>

<script>
// import the lifecycle hooks from vue
import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from "vue";

export default {
setup() {
// use ref to create a reactive state
const message = ref("Hello Vue!");
const counter = ref(0);

// call the lifecycle hooks inside the setup function
onBeforeMount(() => {
console.log("onBeforeMount hook");
});

onMounted(() => {
console.log("onMounted hook");
});

onBeforeUpdate(() => {
console.log("onBeforeUpdate hook");
console.log(counter.value); // old value
});

onUpdated(() => {
console.log("onUpdated hook");
console.log(counter.value); // new value
});

onBeforeUnmount(() => {
console.log("onBeforeUnmount hook");
});

onUnmounted(() => {
console.log("onUnmounted hook");
});

// define a method to increment the counter
const increment = () => {
counter.value++;
};

// return the state and methods to the template
return {
message,
counter,
increment
};
}
};
</script>

In this example, we use the Composition API and lifecycle hooks to create a similar component as before. We import the lifecycle hooks from vue, and call them inside the setup function. We also use ref to create reactive state, and return them to the template.

If we click the button once, we will see the following output in the console:

onBeforeMount hook
onMounted hook
onBeforeUpdate hook
0
onUpdated hook
1

We can see that the lifecycle hooks work as expected with the Composition API.

Additional lifecycle hooks

In addition to the widely employed hooks we have previously discussed, there exist certain supplementary hooks that prove valuable in specific situations. These additional hooks encompass:

  • activated and deactivated: These hooks are only called when your component is inside a <keep-alive> element. They allow you to perform actions when your component is activated or deactivated by the <keep-alive> cache. For example, you can use these hooks to fetch or refresh data when your component is activated.
  • errorCaptured: This hook is called when an error is captured by your component or any of its descendants. It allows you to handle errors gracefully or perform some cleanup tasks. For example, you can use this hook to log errors or display a fallback UI.
  • renderTracked and renderTriggered: These hooks are only available in Vue 3 with the Composition API. They allow you to track which dependencies are used or changed during rendering. For example, you can use these hooks to debug performance issues or optimize reactivity.

Here is an example of using some of these hooks:

<template>
<div>
<h1>{{ title }}</h1>
<keep-alive>
<component :is="currentComponent"></component>
</keep-alive>
</div>
</template>

<script>
import { ref, onErrorCaptured } from "vue";
import Foo from "./Foo.vue";
import Bar from "./Bar.vue";

export default {
components: {
Foo,
Bar
},
setup() {
// use ref to create a reactive state
const title = ref("Hello Vue!");
const currentComponent = ref("Foo");

// use onErrorCaptured to handle errors
onErrorCaptured(error => {
console.error(error);
title.value = "Something went wrong!";
return false; // prevent propagation
});

// switch between Foo and Bar components every 3 seconds
setInterval(() => {
currentComponent.value = currentComponent.value === "Foo" ? "Bar" : "Foo";
}, 3000);

// return

In this example, we use a <keep-alive> element to cache two components: Foo and Bar. We also use onErrorCaptured to handle any errors that may occur in these components. We switch between the components every 3 seconds, and update the title accordingly.

Vue js lifecycle hook error monitoring

To monitor and handle Vue js lifecycle hook errors, you can use the errorCaptured hook, which is triggered when an error is captured by a component. With the help of global Vue.config.errorHandler function, an error is not handled if not called by any component.

Another way to monitor issues in Vue.js applications is to use a third-party tools like Zipy. Zipy helps developers monitor and optimize their web applications by tracking errors and performance issues in real time.

Final thoughts

Lifecycle hooks are an essential feature of vue js, allowing you to perform actions at specific stages of a component’s lifecycle. In vue js they provide support for setting up, updating, and cleaning up components as well as handling errors, events, and side effects.

Through this blog post we have gained an understanding of the significance of lifecycle hooks in vue js and discovered effective ways to utilize them. Additionally, we have explored several common scenarios and examples where these hooks prove to be beneficial in specific situations.

We hope you found this blog article interesting and learned something new.

Happy coding! 😊

This blog was originally published at Zipy.

--

--