Vue3: Components lifecycle (en)
Tags: frontend, webdev, vue, programming
Published: 2024-02-02 15:45:42

> <small>_[Ler em pt/br na Alura!](https://www.alura.com.br/artigos/vuejs-ciclo-vida-componentes)_</small>

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](#what-is-a-lifecycle)
> [Lifecycle hooks with Options API](#lifecycle-hooks-with-options-api)
> [Creation Hooks](#creation-hooks)
> [Mounting Hooks](#mounting-hooks)
> [Update Hooks](#update-hooks)
> [Unmounting Hooks](#unmounting-hooks)
> [Lifecycle hooks with Composition API](#lifecycle-hooks-with-composition-api)
> [Setup Hook](#setup-hook)
> [Syntax with Composition API](#syntax-with-composition-api)
> [Wrapping it up](#wrapping-it-up)_

![Lifecycle of a dandelion](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqdeedbpuvswavlyb975.gif)

---

## 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 <abbr title="Document Object Model">DOM</abbr> 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](https://vuejs.org/guide/essentials/lifecycle.html) 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](https://vuejs.org/guide/essentials/lifecycle.html#lifecycle-diagram):

![Lifecycle diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ckk65lj5sp5rkh5j1qp3.png)

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 <mark>perform actions before your component is added to the DOM</mark> and are also the only ones that work with [server-side rendering](https://vuejs.org/guide/scaling-up/ssr.html#why-ssr).

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.

```vue
<script>
export default {
  beforeCreate() {
    alert('beforeCreate was called')
  }
}
</script>
```

![beforeCreate running](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ojhkjav1wepwqydbguwf.gif)

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.

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

![created running](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yipjn55znf2appiwtfli.gif)

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 <abbr title="Hypertext Transfer Protocol">HTTP</abbr> request to an <abbr title="Application Programming Interface">API</abbr> 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 <mark>before or after inserting the component into the DOM</mark> (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`.

```vue
<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>
```

![beforeMount running](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s878pcwf9xoyjbt4ob9t.gif)

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.

```vue
<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>
```

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 <mark>whenever a reactive property used in your component changes</mark>, 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.

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

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.

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

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 <mark>immediately before or after a component is unmounted.</mark>

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.

```vue
<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>
```

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:

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

<!-- COMPOSITION API -->
<script setup>
console.log("Setup with Composition API");
</script>
```

### 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. <mark>It occurs even before **beforeCreate** and **created** are executed!</mark>

![Moment setup method execution](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/at7orohxxwfa0cynyngk.png)

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>`:

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

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

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

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:

```typescript
function onMounted(callback: () => void): void
```

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

```vue
<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>
```

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>`:

```javascript
import { onMounted, onUpdated } from 'vue';
```

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!