Home / Blog / Migrating from Vue 2 To Vue 3 – Deprecated and Updated Features
Migrating from Vue 2 To Vue 3 – Deprecated and Updated Features

Migrating from Vue 2 To Vue 3 – Deprecated and Updated Features

Charles Allotey
Charles Allotey
May 9th 2023

Vue 3, the latest major version of Vue.js, was released on September 18, 2020 and is a complete rewrite of Vue 2, with a focus on better performance, smaller bundle sizes, better TypeScript and IDE support, and improved scalability. However, migrating from Vue.js 2 to Vue.js 3 is not always straightforward, and developers need to be aware of certain changes and potential issues that may arise during the process.

In this article, we will discuss some of the key features from Vue.js 2 that have either been deprecated or updated in the release of Vue.js 3. This should help you know the necessary code changes should you decide to migrate your Vue.js 2 project to Vue.js 3.

Deprecated Vue 2 Features

As you migrate from Vue 2 to Vue 3, it's important to keep in mind the deprecated features. These are the features that have been removed or modified in the latest version, and using them can cause errors or compatibility issues. In this section, we'll explore some of the deprecated features in Vue 2 and what changes you need to make in Vue.js 3.

Filters

In Vue 2 you could to define filters that can be used to apply common text formatting.

<template>
  <h1>Bank Account Balance</h1>
  <p>{{ accountBalance | currencyUSD }}</p>
</template>

<script>
  export default {
    //...
    filters: {
      currencyUSD(value) {
        return '$' + value
      }
    }
  }
</script>

It was a very quick and cool way to add formatting to reactive text but it brought a deeper curve to learning Vue and some implementation costs. In Vue 3 you can achieve the same thing by using a computed property.

<script setup>
const accountBalance = ref(0)
const accountInUSD = computed (() => {
return '$' + accountBalance.value
})
</script>

<template>
  <h1>Bank Account Balance</h1>
  <p>{{ accountInUSD }}</p>
</template>

Functional Components

Functional components in Vue.js are components that do not have any internal state, and their main purpose is to render content based on the input props. They are lightweight and faster compared to regular components, as they do not involve the overhead of managing component instances.

In Vue.js 2, functional components provided a more performant alternative when component state was not needed.

<template functional>
  <component 
    :is="`h${props.level}`" 
    v-bind="attrs" 
    v-on="listeners"
  >
    <slot></slot>
  </component>
</template>

<script>
export default {
  props: ["level"],
};
</script>

In Vue 3, the performance difference for stateful components is so negligible that functional single file components are removed. So no need to burden yourself with extra syntax. Just use those stateful components everywhere without the performance hit!

<template>
  <component 
    :is="`h${props.level}`" 
    v-bind="$attrs" 
  >
    <slot></slot>
  </component>
</template>

<script>
export default {
  props: ["level"],
};
</script>

Keycode Modifier

In some applications, we use keyboard keys to trigger custom events. In Vue 2 we could not explicitly state these keys but had to use their associated keycodes.

//keycode 75 represents the letter 'k'
<input v-on:keyup.75="doSomething" />

Say goodbye to the hassle of using keycodes in Vue 2! With the release of Vue 3, you can now easily call the values instead, making your development process smoother and more efficient. No more struggling to remember keycodes, just use the values and you're good to go.

<input v-on:keyup.k="doSomething" />
<input v-on:keyup.arrow-up="doSomethingElse" />

Updated Vue 2 features

As you migrate from Vue 2 to Vue 3, it's not all about deprecations and breaking changes. There are also several features in Vue.js 2 that have been updated or enhanced in Vue 3. These improvements can make your development experience more enjoyable and efficient. In this section, we'll explore some of the updated features in Vue.js 2 that you can take advantage of in Vue 3.

Multiple V-models

In the previous version of Vue (Vue 2.7 >), a component was only restricted to a single v-model. Supporting v-model on a component is done by emitting input and accepting a value  prop.

//MyInput.vue
<template>
<input 
  @input="$emit('input', $event.target.value)" 
  :value="value" 
/>
</template>
<script>
export default {
  props:{
    value: String
  }
}
</script>

//App.vue
<MyInput v-model="name" />

Now with the release Vue 3, you can create multiple v-model bindings on a single component instance by leveraging the ability to target a particular prop and event as we learned before with v-model arguments. Each v-model will sync to a different prop, without the need for extra options in the component. Here's an example:

<template>
  <UserName
    v-model:first-name="firstName"
    v-model:last-name="lastName"
  />
</template>

<script>
import UserName from './UserName.vue';

export default {
  components: {
    UserName,
  },
  data() {
    return {
      firstName: '',
      lastName: '',
    };
  },
};
</script>

In the UserName component, you can define the props and emits like this:

<template>
  <div>
    <input
      type="text"
      :value="firstName"
      @input="$emit('update:firstName', $event.target.value)"
    />
    <input
      type="text"
      :value="lastName"
      @input="$emit('update:lastName', $event.target.value)"
    />
  </div>
</template>

<script>
export default {
  props: {
    firstName: String,
    lastName: String,
  },
  emits: ['update:firstName', 'update:lastName'],
};
</script>

This way, you can create two-way bindings between state and form inputs using the v-model directive.

Comprehensive $attrs

In both Vue 2 and Vue 3, $attrs is an object that contains all the attributes that are not declared as props or emitted events in a component. It’s useful for handling attributes that have no need to be declared as props

However, in Vue 3, $attrs is even more powerful and comprehensive. It includes all the attributes that are not declared by the component's props or emits options, including class, style, and v-on listeners. This means that you can use $attrs to pass down event listeners to child components as well, which was not possible in Vue 2 where you had to access attributes passed to your components with this.$attrs, and event listeners with this.$listeners as separate entities .

Another change between Vue 2 and Vue 3 is that in Vue 2, $attrs does not include class and style attributes by default while all other attributes are. In Vue 3, class and style attributes are included in $attrs by default, which makes it easier to apply them to a different element.

Here's an example of how $attrs changes in Vue 2 and Vue 3:

//input.vue
<template>
  <label>
    <input type="text" v-bind="$attrs" />
  </label>
</template>

<script>
export default {
  inheritAttrs: false
}
</script>

when used like this:

<my-component id="test-id" class="test-class"></my-component>

html is rendered as follows:

//Vue 2
<label class="test-class">
  <input type="text" id="test-id" />
</label>

//Vue 3
<label>
  <input type="text" id="my-id" class="my-class" />
</label>

In both versions of Vue, $attrs is a powerful feature that allows you to pass down attributes to child components without having to declare them as props in the parent component. It is especially useful for styling purposes and for passing down event listeners. However, in Vue 3, $attrs is even more comprehensive and includes more types of attributes by default.

Fragments

The introduction of fragments represents another important change in Vue 3 over Vue 2. We can now declare multiple root elements in a single template. This makes for cleaner code and fixes the occasional style issue brought on by unnecessary wrappers. Let’s review an example

<template>
<!-- In Vue 2 this emits "The template root requires exactly one element" -->
<div></div>
<div></div>
</template>

Conclusion

Hope you enjoyed reading this article. This article is not comprehensive and only highlights a few of the changes in Vue 2 and Vue 3. Definitely checkout the Vue.js Migration guide for a breakdown of even more changes or if you are looking a practical guide on these changes and more on how you can migrate your Vue 2 project to Vue 3 then don’t miss out on our next Vue 2 to Vue 3 workshop. Guaranteed to be an intense, challenging, and fun experience as you learn more on these changes.

Migrating from Vue 2 to Vue 3 can seem like a daunting task, but it's worth the effort. With the updated features and improved performance, Vue 3 will make your development experience more enjoyable and efficient. However, it's important to keep in mind the deprecated features and to make the necessary changes to your code. So, don't be afraid to take the leap and upgrade to Vue 3. Your projects and clients will thank you for it!

Start learning Vue.js for free

Charles Allotey
Charles Allotey
Charles is a Frontend Developer at Vueschool. Has a passion for building great experiences and products using Vue.js and Nuxt.

Latest Vue School Articles

Secure Your Vue.js 3 App: Laravel 11 Middleware with Pinia and Vue Router

Secure Your Vue.js 3 App: Laravel 11 Middleware with Pinia and Vue Router

Learn how to secure your Vue.js 3 app by creating custom Laravel 11 middleware, utilizing Pinia for state management, and implementing Vue Router guards for enhanced protection.
Mostafa Said
Mostafa Said
What is a Race Condition in Vue.js?

What is a Race Condition in Vue.js?

A race condition is where an app’s proper behavior is dependent on the sequence or timing of other uncontrollable events. In this lesson, learn how to fix a race condition in a Vue.js Composable.
Daniel Kelly
Daniel Kelly

Our goal is to be the number one source of Vue.js knowledge for all skill levels. We offer the knowledge of our industry leaders through awesome video courses for a ridiculously low price.

More than 120.000 users have already joined us. You are welcome too!

Follow us on Social

© All rights reserved. Made with ❤️ by BitterBrains, Inc.