DEV Community

Cover image for Vue3: Components lifecycle (en)
Angela Caldas
Angela Caldas

Posted on • Edited on

Vue3: Components lifecycle (en)

Ler em pt/br na Alura!

If you have recently started learning about a framework or Front-End library, you may have already come across the term "lifecycle" of a component and may have wondered what exactly it means.

In this article, we will understand the main lifecycle methods that Vue.js offers us and their implementations with Options API and Composition API!

Table of Contents
What is a lifecycle
Lifecycle hooks with Options API
Creation Hooks
Mounting Hooks
Update Hooks
Unmounting Hooks
Lifecycle hooks with Composition API
Setup Hook
Syntax with Composition API
Wrapping it up

Lifecycle of a dandelion


What is a lifecycle?

In Vue, each component goes through several steps: basically, it is created, it observes data, it mounts its elements in the DOM and updates them when any data is modified until, eventually, it is destroyed. Throughout this process, the component uses several functions called lifecycle methods or lifecycle hooks.

The lifecycle hooks are predefined methods that are executed at specific times during the useful life of a component, i.e. the period of time in which a component exists, is active and performs its functions in an application or software system.

These methods can also be used by us, developers, and allow us to control the component's behavior, perform operations at specific times and interact with the DOM or other components.


Lifecycle hooks with Options API

With the Options API we have access to eight main lifecycle methods (which we will call hooks from here on): beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeUnmount and unmounted.

The moment at which each hook is executed in the component instance is demonstrated by the diagram below, taken from the official Vue.js documentation:

Lifecycle diagram

To facilitate the study of this article, we'll categorize them into groups: creation, mounting, update, and unmounting hooks.


Creation Hooks

The creation hooks are the first hooks to run in a component. They allow you to perform actions before your component is added to the DOM and are also the only ones that work with server-side rendering.

Here we will learn about the hooks beforeCreate and created.

beforeCreate

beforeCreate is executed as soon as a component is initialized. At this time, computed states and properties have not yet been processed.

<script>
export default {
  beforeCreate() {
    alert('beforeCreate was called')
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

beforeCreate running

In the code above, alert() is executed before the component is rendered.

This hook is very useful, for example, to make an authentication request. Depending on the result of the request, the global state (Vuex or Pinia) is configured accordingly, allowing you to handle authentication before any content is displayed on the screen.

created

created is also executed before the component is mounted in the DOM, however, at this stage all states, computed properties, methods and watchers have already been processed and are ready to be accessed.

<script>
export default {
  data() {
    return { message: 'BEM VINDO À ALURA' }
  },
  created() {
    alert(this.message)
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

created running

In the code above, alert() is executed before the component is rendered, but we already have access to the message property processed in our data().

This is a very useful hook to make a HTTP request to an API and update the component state with these data, which will be rendered in the DOM.


Mounting Hooks

Mounting hooks allow you to access the component immediately before or after inserting the component into the DOM (first render), typically to access or modify elements.

Here we will learn about the hooks beforeMount and mounted.

beforeMount

beforeMount is very similar to created, with the key distinction lying in the timing of their execution::

  • created is triggered after component creation and allows access to data options, but before the DOM is mounted;
  • beforeMount is triggered immediately before mounting the DOM, right after a pre-compilation of the component's template and style.
<script>
export default {
  data() {
    return { pageTitle: 'Loading...' }
  },
  beforeMount() {
    // Simulating the return of an API
    setTimeout(() => {
      const apiResponse = { title: 'Page Title' }
      this.pageTitle = apiResponse.title
    }, 2000)
  },
}
</script>

<template>
    <h1>{{ pageTitle }}</h1>
</template>
Enter fullscreen mode Exit fullscreen mode

beforeMount running

In the code above, we simulate an API call that takes two seconds to update the page title. The same effect would be achieved using created.

mounted

mounted is executed immediately after the component is mounted. At this stage, the component becomes functional: properties from data() are injected into the template, elements are rendered, and DOM manipulation becomes possible.

<script>
export default {
  data() {
    return {
      items: [
        { id: 1, name: 'Item 1' },
        { id: 2, name: 'Item 2' },
        { id: 3, name: 'Item 3' }
      ]
    }
  },
  mounted() {
    const listItems = this.$refs.listItem

    listItems.forEach((item) => {
      item.addEventListener('click', () => {
        alert(`You've clicked: ${item.textContent}`)
      })
    })
  }
}
</script>

<template>
  <ul>
    <li v-for="item in items" :key="item.id" ref="listItem">
      {{ item.name }}
    </li>
  </ul>
</template>
Enter fullscreen mode Exit fullscreen mode

In the example above, we created a dynamic list in the template, but the click events for each <li> in the list were only inserted after the component's mounted() hook is executed.


Update Hooks

Update hooks are executed whenever a reactive property used in your component changes, forcing it to re-render. This execution can be immediately before or after this change.

Here we will learn about the hooks beforeUpdate and updated.

beforeUpdate

beforeUpdate runs immediately after a reactive property is changed, but immediately before the component is re-rendered on screen.

<script>
export default {
  data() {
    return {
      counter: 0,
      history: []
    }
  },
  beforeUpdate() {
    this.history.push(this.counter)
  },
  methods: {
    increment() {
      this.counter++
    }
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

In the code above, for example, whenever counter is updated, we will save its new value in the array history before this data is updated on screen. beforeUpdate is also widely used for debugging operations to identify when component rendering is activated, for example.

updated

updated is executed immediately after a re-render of the component caused by a reactive data change, being very useful for creating side effects related to the DOM.

<script>
export default {
  data() {
    return {
      items: []
    }
  },
  methods: {
    addItem(item) {
      this.items.push(item)
    }
  },
  updated() {
    const listContainer = this.$refs.listContainer
    listContainer.scrollTop = listContainer.scrollHeight
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

In the code above, whenever a new item is added to the list using the addItem method, the component is updated, and the updated hook is called. Inside the updated hook, we implement an auto-scroll functionality so that the list scrolls to the last item whenever new items are added to the list.


Unmounting Hooks

Unmounting hooks, also called destruction hooks (a bit dramatic, right?) are executed immediately before or after a component is unmounted.

Here we will learn about the hooks beforeUnmount and unmounted.

beforeUnmount

beforeUnmount is executed immediately before the component is unmounted. Importantly, at this point the component is still fully functional, so it's a great step to perform clean up functions such as removing event listeners, deleting variables, performing logout actions, etc.

<script>
export default {
  data() {
    return {
      socket: null
    };
  },
  mounted() {
    this.socket = new WebSocket('wss://example.com/socket');
    this.socket.addEventListener('message', this.handleMessage);
  },
  beforeUnmount() {
    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
      this.socket.removeEventListener('message', this.handleMessage);
      this.socket.close();
    }
  },
  methods: {
    handleMessage(event) {
      // Logic for dealing with the received WebSocket messages
    }
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

In this example, the component creates a WebSocket connection when it is mounted and adds a listener for WebSocket messages. In beforeUnmount, it checks if this connection is open (WebSocket.OPEN) and, if so, closes the connection using this.socket.close(). This ensures that the connection is properly closed before the component is destroyed, preventing resource leaks and unexpected behavior.

unmounted

unmounted happens immediately after the component is unmounted from the DOM tree, so practically everything that existed in relation to that component is considered "destroyed", as emphasized by the documentation itself:

A component is considered unmounted after:

  • All its child components have been unmounted;
  • All its associated reactive effects (rendering effects and data created during setup()) have been stopped.

We can conclude that, at this stage, there is not much that can be done to a component. In general, unmounted is also used for clean up functions.


Lifecycle hooks with Composition API

The Composition API, which represents the latest syntax for a Vue component, has introduced alterations to the lifecycle methods. The most noticeable changes include the removal of the hooks beforeCreate and created, along with subtle modifications to their names and syntax.

These changes came to boost the performance of our Vue application, in addition to providing better compatibility with TypeScript. All of this was possible thanks to the new hook setup().

Let's understand a bit more about this.


Setup Hook

The setup() hook in Vue 3 is an essential part of the Composition API, which is a more flexible, functional, and modular approach to creating components compared to the Vue 2 syntax. It is used to configure and initialize the state, props, methods and other options of a Vue component.

However, despite being a feature of the Composition API, it is entirely possible to use setup() within the Options API as a facilitator for your code. See what the hook syntax looks like in both cases:

<!-- OPTIONS API -->
<script>
export default {
  setup () {
    console.log("Setup with Options API");
  }
}
</script>

<!-- COMPOSITION API -->
<script setup>
console.log("Setup with Composition API");
</script>
Enter fullscreen mode Exit fullscreen mode

Extinction of beforeCreate and created

If we go back to the lifecycle diagram we saw at the beginning of this article, we can see that setup() is the first creation method executed in a Vue component. It occurs even before beforeCreate and created are executed!

Moment setup method execution

This way, any code that could be used within these hooks can simply be inserted into setup(). Do you remember the API request simulation we exemplified earlier? See how it would look using <script setup>:

<script setup>
import {ref} from 'vue';

let pageTitle = ref('Loading...');

setTimeout(() => {
  const apiResponse = {title: 'Page Title'};
  pageTitle.value = apiResponse.title;
}, 2000);
</script>
Enter fullscreen mode Exit fullscreen mode

With the code above, we will have the same effect as with created!

Syntax with Composition API

Although we no longer have beforeCreate and created, the other hooks are still present in the Composition API, but with a slightly different syntax from what we have seen earlier, as we will now be calling each of them within setup ().

It is important to keep in mind that the moment of execution for each of these hooks within the component remains the same! Therefore, we will focus here only on their syntax, starting with the change in names, which are now: onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount and onUnmounted.

To grasp the new syntax more effectively, it's essential to recognize that within the Composition API, every hook works as a function that takes a callback function as its parameter. For example, here is the onMounted typing:

function onMounted(callback: () => void): void
Enter fullscreen mode Exit fullscreen mode

Based on this, we can use our hooks in the following ways:

<script setup>
import { ref, onMounted } from 'vue';

const myMessage = ref('A random message')

const showMessage = () => {
  alert(myMessage.value);
};

// Method 1:
onMounted(showMessage);

// Method 2:
onMounted(() => showMessage());

// Method 3:
onMounted(() => {
  showMessage()
}
</script>
Enter fullscreen mode Exit fullscreen mode

Let’s understand the subtle differences between each of them:

  • Method 1: onMounted(showMessage)

This way, you are directly passing the showMessage function as an argument to onMounted. The showMessage function will be called directly when onMounted is executed. This is useful when the showMessage function does not need additional arguments.

  • Method 2: onMounted(() => showMessage())

Here you wrap the showMessage call in an anonymous callback function. The callback function will be executed when onMounted is triggered and then it will call showMessage(). This method is useful when you need to pass arguments to showMessage.

  • Method 3: onMounted(() => { showMessage() })

This way is similar to Method 2, but you are using an anonymous callback function with a block of code enclosed in curly braces { }. This is useful when you need to perform multiple actions or logic within onMounted in addition to calling showMessage.

The main difference between methods 2 and 3 is that Method 3 allows you to include multiple lines of code and perform multiple actions within onMounted. Method 2 is more concise and direct, while Method 3 is more expandable when you need more complexity.

The above syntax can be used with any Composition API hook, not just onMounted. Furthermore, you can use the same lifecycle hook multiple times within a single component! Also note that for the hooks you intend to utilize in your component, it's crucial to import them within the <script setup>:

import { onMounted, onUpdated } from 'vue';
Enter fullscreen mode Exit fullscreen mode

This is another particularity of the Composition API: by importing from the API only what is necessary for each component, we improve the performance of our application, unlike what happens in the Options API, where the entire API is already completely imported into the components behind the scenes.


Wrapping it up

In this article, we delved into the different lifecycle methods provided by Vue.JS and explored how they can enhance our applications.

I trust you found the information enjoyable and that it added to your understanding of Vue. Until next time!

Top comments (2)

Collapse
 
deploydesexta profile image
Gabriel Godoy

A simple but well-written article about one of my biggest fascinations on Vue. You did improve my Friday afternoon!

Congrats on the article.

Collapse
 
sucodelarangela profile image
Angela Caldas

Thank you so much for the kind words, I'm really glad my article's been of use for you, Gabriel! <3