What's new in Vue.js?

Vue is a powerful and flexible JavaScript framework - It’s worth reflecting on the latest features available today and why Vue 3 might be the best choice for your next project.

16-11-2021
Bcorp Logo
Why Vue 3 might be the best choice for your next project.

Vue is a powerful and flexible JavaScript framework that is being updated all the time with regular releases. While Vue 3 first became available in September 2020 more and more teams are now making the leap from Vue 2. It’s worth reflecting on the latest features available today and why Vue 3 might be the best choice for your next project.

Even if your team is still using Vue 2, the modular approach to Vue framework development means you can bring some of these changes in to your codebases today. This flexibility is one of the great advantages of Vue.

Why Vue 3 might be the best choice for your next project.

Composition API

Without a doubt, the most talked about feature in Vue 3 has been the composition API. This alternative way to write, structure and reason about your code has a lot of advantages. I find it very similar to hooks in React. Let’s refactor code written in with the Options API to leverage the composition API. Here’s the options version:

```js
export default {
  data() {
    return {
      message: "Hello",
    };
  },
  methods: {
    logIt() {
      console.log(`Vue says: ${message}`)
    },
  },
  mounted() {
    this.logIt()
  }
}
```

With a single function this doesn’t look too overwhelming but with multiple functions this can quickly get much longer and more complicated. Following the flow of the data can be quite challenging. We’re setting state in the data method and providing functions to interact with state in the methods object and mounted method. For more complex use cases, we could be using more life-cycle methods and computed properties. It can look like spaghetti code very quickly.

With the composition API, we have a new property for the options object, `setup`, and we can write the code like this:

```js
export default {
  setup() {
    const message = ref("Hello");
    const logIt = () => console.log(`Vue says: ${message.value}`);
    
    onMounted(() => {
      logIt();
    }
    
    return { message };
  }
}
 
```

For me, one of the biggest advantages here is that we get to write plain JavaScript in the setup method. We can see the flow of the data really clearly and reason about our code in a much more concise way.

Why Vue 3 might be the best choice for your next project.


This logic can be shared between components more easily which allows for more composable codebases. This increase developer productivity and reduces the amount of repeated work in your teams. More recently, the composition API has got even more expressive with the `setup` script attribute.

```js
<script setup>
    const message = ref("Hello");
    const logIt = () => console.log(`Vue says: ${message.value}`);
    
    onMounted(() => {
      logIt();
    }
    
    return { message };
</script>
```

No need for the options API at all! This feels largely inspired by another framework called Svelte and I like it. This has fundamentally shifted how I write and structure Vue applications making things more testable and explicit.

TypeScript

In conversations I have with developers, TypeScript can be a divisive topic. If you are someone who loves TypeScript though, changes in Vue 3 are going to make you very happy (if you’re not you can ignore this bit).

Vue has effectively been rewritten from the ground up to be TypeScript compatible. There is typing available on every level allowing you to leverage tooling to help eliminate a whole category of bugs.

Migrating to TypeScript in a project can be incremental allowing you to start your TypeScript journey with new components and gradually refactor old parts of your application.

Suspense

It’s really common for components to need to perform an asynchronous operation before they can be rendered properly. Whether this is some kind of data fetch or calculation, developers need to handle the loading state.

The suspense component allows developers to provide a fallback template that can be used when the asynchronous operations have yet to be resolved.

The component has two slots, the default and the fallback, which each can take one child node. If the default can’t be rendered because of some blocking work, the fallback will be displayed instead.

This is more declarative and can allow your code base to be more explicit when considering loading and error states. Here’s what it looks like in code:

```js
<template>
  <Suspense>
    <template #default>
      <p>This will be rendered with the data ... </p>
    </template>
    <template #fallback>
      <p>Data loading ... </p>
    </template>
  </Suspense>
</template>
```

Multiple root elements

Like the slots in the suspense components, all templates in Vue 2 are limited to a single root element. This would often mean having to introduce a wrapping div that added no context or support to your actual application.

It is now possible to have multiple root elements, allowing your HTML to feel more semantic and meaningful.

```js
<template>
  <h1>My heading</h1>
  <p>My content</p>
</template>
```

Multiple v-models

In Vue, we use v-model for two-way binding. This is mostly for form elements. In Vue 2, we could only bind a single Vue model. This meant we’d pass through an object with all of the keys. In Vue 3, we can bind any number of v-models to our custom components.

So, instead of passing in a whole data object like this

```js
<template>
  <survey-form v-model:data="data" />
</template>
```
we can be more explicit and pass in each field.
```js
<template>
  <survey-form v-model:name="name" v-model:email="email" />
</template>
```

Global mounting

Vue 3 introduces a new global API, createApp. This changes how we instantiate and mount our applications. It also updates how we inject dependencies to any component inside of our application.

Previously, we started each application with a Vue instance.

```js
const vm = new Vue({})
vm.use(router);
```
Now, we use an application instance.
```js
import { createApp } from 'vue';
const app = createApp({})
app.use(router);
```

While the difference may seem trivial, this reduces the amount of global mutations that were possible previously. While testing, it’s now easier to isolate cases and we can have multiple apps running to consider different configurations.

All of the global and internal APIs have been restructured to be tree-shakable as well, allowing for dead code to be eliminated more effectively. This allows for smaller bundle sizes and more efficient code.

Teleport

Vue encourages us to build in a component focused way. With teleport, though, you can render a component in a different place in the DOM tree - even if that is not in your app’s scope! This is similar to the well-known concept of `Portal` in React and in Vue 2 it’s available through the third-party plugin `portal-vue`.

This is particularly useful when thinking about reusable modals. Guaranteeing that our modal will always be on top can be a challenge. Traditionally, we’d deal with this using the z-index but this can cause a challenge if you have multiple competing elements.

Teleport takes one property, `to`, and a default slot.

```js
<SomeComponent>
  <Teleport to="#the-target">
    <Modal />
  </Teleport>
</SomeComponent>
<!-- This should be before closing the body tag in index.html -->
<div id="the-target"></div>
```

In the above example, the `Modal` will render in `the-target` div, even though it is inside `SomeComponent`. This helps you keep your code structured properly and not having to fight with `z-index` conflicts.

Whether you’re migrating your code from Vue 2 to Vue 3 or just getting started with Vue, we offer instructor-led training that can help make the transition smoother.


Would you like to know more?

If you found this article interesting you might be interested in our Vue.js Training Course

Share this post on:

We would love to hear from you

Get in touch

or call us on 020 3137 3920

Get in touch