Creation Hooks

Learn and practice the hooks related to object creation—beforeCreate and created.

The first two lifecycle hooks we’re going to look at are coincidentally the first ones that get executed whenever a component initializes—beforeCreate and created. Every component, and even the Vue app itself, knows these. Let’s look at the diagram below to understand the context of these hooks:

Notice that when these two hooks get executed, neither the template nor any reactivity is around—so what exactly is the use of these two hooks?

We’ll answer this question later in the lesson. However, we first need to know how we can add these hooks to use them.

Adding the hooks

Adding lifecycle hooks is straightforward. Unlike methods, computed fields, props, or data, they don’t live in their own category. They’re not nested in an extra object but directly live in the component’s object. We describe hooks as single functions that don’t take any arguments. We can define them on any Vue instance, either a Vue app or a single Vue component.

Press + to interact
import { createApp } from 'vue'
createApp({
// data() { ... },
// computed: ...,
// methods: ...,
beforeCreate() {
console.log('Hello from beforeCreate in app')
},
created() {
console.log('Hello from created in app')
}
})

Notice that we also added the data, computed, and methods keys to illustrate where lifecycle hooks live. An alternative syntax is to define them as object keys and use anonymous functions or arrow functions instead, as illustrated below:

Press + to interact
import { createApp } from 'vue'
createApp({
// data() { ... },
// computed: ...,
// methods: ...,
beforeCreate: function() {
console.log('Hello from beforeCreate in app')
},
created: () => {
console.log('Hello from created in app')
}
})

We can also add them the very same way in a single-file component, as illustrated below:

Press + to interact
<template>
<!-- ... -->
</template>
<script>
export default {
beforeCreate() {
console.log('Hello from beforeCreate in component')
},
created() {
console.log('Hello from created in component')
}
}
</script>

Note: Generally, it’s considered good practice to add the hooks in the order of their execution after the methods. This way, we always know where to look for them and don’t confuse them with any other part of the component.

Examining the hooks

Now that we know how to add the hooks, we can examine them. Let’s build a basic Vue app that does nothing but execute these two hooks. First, we’ll look at things like data, computed, and some instance properties, such as $el, to understand which items are available.

We can click “Run” further down to execute the code. Feel free to experiment for a bit! You should think about the following questions as you do so: What things are there and what aren’t? Is it possible to do anything with the Vue app in these hooks? What happens when we overwrite parts of the app in the hooks?

import { createApp } from 'vue'

const app = createApp({
  render() {
    return 'Open your browser dev tools to inspect.'
  },
  data() {
    return {
      message: 'Hello!'
    }
  },
  computed: {
    result() {
      return 2 + 2
    }
  },
  beforeCreate() {
    console.log('beforeCreate:')
    console.log('Hook arguments: ' + JSON.stringify(arguments))
    console.log('this: ' + typeof this)
    console.log('this.message: ' + typeof this.message)
    console.log('this.result: ' + typeof this.result)
    console.log('this.$el: ' + typeof this.$el)
  },
  created() {
    console.log('<h2>created:</h2>')
    console.log('Hook arguments: ' + JSON.stringify(arguments))
    console.log('this: ' + typeof this)
    console.log('this.message: ' + typeof this.message)
    console.log('this.result: ' + typeof this.result)
    console.log('this.$el: ' + typeof this.$el)
  }
})
app.mount('#app')

A simple Vue app to investigate the behavior of the two lifecycle hooks, beforeCreate and created

We might notice a few things:

  • First of all, this is always around. The Vue component has been initialized, at least on a class level.
  • Both data and computed are not around at beforeCreate but show up once created is called. They need to be initialized in between.
  • $el is not around, even at created. This must have to do with templating.
  • None of these hooks have arguments.

Now, how can we leverage this?

Use cases

Generally, we can’t do very much in these two hooks, especially in beforeCreate. These hooks help debug and do Vue-agnostic work upfront though. For example, we can trigger API calls very early on. We can store the promises outside the Vue component and attach them to the component’s data later on.

We’ve prepared a backend that offers an API that returns five random poems, including some metadata, as JSON objects. So let’s say we want to fetch these as early as possible and not block any setup of Vue, essentially making the initial setup feel faster.

Let’s see if we can use beforeCreate and created to fetch poems as early as possible and assign them to the data in App.vue. Also, add a loading message to App.vue to let the user know that there was no error, and the App fetches the content. Now, try fetching the poems in an async-computed property. Is there a noticeable drop in performance?

<template>
  <div>
    Loaded {{ poems.length }} poems
    <div v-for="(poem, index) in poems" :key="index">
      <h2>{{ poem.title }}</h2>
      <p>{{ poem.content }}</p>
      <p>by {{ poem.poet.name }}</p>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    poems: {
      type: Array,
      required: true
    }
  }
}
</script>

A simple Vue app that fetches a list of poems upfront and displays them with a premade component

In the hint below, we can find a solution for the above problem.

These hooks are pretty helpful for upfront work and speed up the setup of an app. To make an app respond faster, shifting things like data fetching or state negotiation to a time as early as possible is very useful.