Migrating from Vue 2 To Vue 3 – Deprecated and Updated Features
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!