the/experts. Blog

Andrea Busse
Andrea Busse

Posted on

Vue3 - New Features and Improvements

What is Vue?

In short, VueJS is a progressive frontend framework that facilitates you to build user interfaces. For that, it builds on top of HTML, CSS and JavaScript, not unlike Angular or React.
Since version 2.6, the core team around Evan You has introduced a lot of new major features in Vue3, the most important ones of which will be highlighted here.

Composition API

The introduction of the Composition API is arguably the biggest new feature of Vue3.
It introduces a new way of building components in Vue, and can be used instead of the existing Options API.
The Options API declares options while the Composition API relies on importing functions. This leads to a vastly different setup of Vue components depending on which API you choose to use. Take a look at these components from the Vue documentation:

Options API:

import { createApp } from 'vue'

createApp({
  data() {
    return {
      count: 0
    }
  },
mounted() {
    console.log(`The initial count is ${count.value}.`)
}
}).mount('#app')

<div id="app">
  <button @click="count++">
    Count is: {{ count }}
  </button>
</div>
Enter fullscreen mode Exit fullscreen mode

Composition API:

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

// reactive state
const count = ref(0)

// functions that mutate state and trigger updates
function increment() {
  count.value++
}

// lifecycle hooks
onMounted(() => {
  console.log(`The initial count is ${count.value}.`)
})
</script>

<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>
Enter fullscreen mode Exit fullscreen mode

One of the main reasons for introducing the Composition API is readability. While that does not seem a big issue for small components such as the above, the reason becomes clear when looking at bigger components.
Look at the example below, taken from the official Vue Docs. The code on each side does the same, but the Composition API allows you to group and organize your code way better than the Options API does.

Comparison of the Options API and Composition API

Another benefit of the Composition API is that it allows for way greater code reusability within the same compositions and contexts. In the Options API, you often needed Mixins to achieve the same level of reusability.
You can now also make use of Hooks, which can be defined in the hooks directory and imported into components as needed.

TypeScript Support

While you could use TypeScript in Vue2, support for it was not out-of-the-box, and implementing it always felt quite laborious and unintuitive. Thankfully, Vue3 now comes with built-in support, making writing your App in TypeScript a lot easier.

Lifecycle Hooks

Vue3 uses slightly different names for some of its lifecycle hooks. The main change you will notice when looking at their documentation is that all names of the hooks are now prefixed with 'on-'. This was done to conform to the naming conventions of other frameworks, such as React. When you use Vue3 with the Options API known from Vue2, the naming does not change, except for beforeDestroy(), which was renamed to be beforeUnmount(), and destroyed(), which was renamed to unmounted(). This was done to more accurately depict what the lifecycle hook really does.
Vue3 also introduces two new lifecycle hooks that are available in development mode only, and are meant to facilitate debugging your application:

onRenderTracked(): is called when a reactive dependency has been tracked by the component's render effect
onRenderTriggered(): is called when a reactive dependency triggers the component's render effect to be re-run

Note: Neither of these two hooks can be used during server-side rendering.

Teleport

Consider the following scenario: A part of a component's template belongs to it logically, but from a visual standpoint, it should be displayed somewhere else in the DOM, outside of the rest of the Vue application.
Mostly this is used for modals. Instead of writing somewhat convoluted CSS to correctly position our modal, we can use the Teleport component which takes care of the messy parts for us:

<button @click="open = true">Open Modal</button>

<Teleport to="body">
  <div v-if="open" class="modal">
    <p>Hello from the modal!</p>
    <button @click="open = false">Close</button>
  </div>
</Teleport>
Enter fullscreen mode Exit fullscreen mode

The to-target of Teleport expects a CSS selector or an actual DOM node. In this example, we are essentially telling Vue to "teleport this template fragment to the body tag". The template fragment is added as the last element inside the body tag.
Note: The teleport to-target must already exist in the DOM when the component is mounted.

Suspense

Remember all those times you’ve written components and automatically added in v-if="!isLoading" and a v-else on another second element to render something while your content loads?
With Suspense, Vue3 and the Composition API take care of this logic for you. The template below shows an example syntax. As you can see, it’s a lot nicer and easier to read than the v-if approach.

<Suspense>
  <template #default>
    <MyData />
  </template>
  <template #fallback>
    <div>Loading...</div>
  </template>
</Suspense>
Enter fullscreen mode Exit fullscreen mode

But how does Vue know when to use Suspense? This is where the Composition API comes in. All you need to do is make the setup method async. Suspense 'recognizes' when an async call is performed, and while your asynchronous code is loading, the fallback is displayed.

export default {
  async setup () {
    const data = await fetchData()
    return { data }    
  }
}
Enter fullscreen mode Exit fullscreen mode

This feature drastically but elegantly reduces the boilerplate code required to make asynchronous external calls.

Fragments

Component1

<template>
  <DoStuffComponent class="cssClass"/>
</template>
Enter fullscreen mode Exit fullscreen mode

DoStuffComponent

<template>
  <ComponentOne />  // ← inherits cssClass styles
  <ComponentTwo />  // ← inherits cssClass styles
</template>
Enter fullscreen mode Exit fullscreen mode

While Vue will log a warning to your console, this can still be considered to be a sub-optimal developer experience.

Multiple v-models

Vue achieves two-way binding through the v-model directive.
Up until now, it was only possible to use one v-model per component or form element. Vue3 introduces the possibility of having multiple v-models, and facilitates this by effectively naming each of them:

<NameComponent
  v-model:firstName="firstName"
  v-model:lastName="lastName"
/>
Enter fullscreen mode Exit fullscreen mode

Summary

These are the most notable changes and additions made in Vue3.
Other changes worth reading up upon include Template References, the changes in the Configuration API, and the Streamlining of the Custom Directive API.

Sources

Discussion (0)