Back to Vue 2 to Quickly Master Vue 3

Get a good grasp of Vue 3 features by comparing them with Vue 2 ones.

Sang Nguyen
JavaScript in Plain English

--

Photo by Rovshan Allahverdiyev on Unsplash

I haven’t worked with Vue.js on a real work project for a long time. Recently, I’ve researched more for Vue 3 in my free time. I found many interesting things from Vue 3. I think we will have a question when we start to work with a new version of any framework. This question is “How to do … like when I worked with the old version of this framework?” I also realized that we have a good way to learn new knowledge faster which is to take us back to an old version of that and apply new knowledge to it. That’s why I will list and compare some cases with Vue 2 and Vue 3. I think it will help us learn Vue 3 quickly.

Option API and Composition API

Composition API is one of the best features Vue 3 provides for us. The Composition API has many interesting features. That’s why we choose Vue 3 Composition API and Vue 2 Option API to start this article. Firstly, I’ll show a basic example of Vue.js components with the Composition API and Option API:

Basic component with Vue 2 using Option API:

Basic component with Composition API in Vue 3:

If you want to write it shorter in Vue 3, you can try with setup script:

Above, I’ve shown three ways to make a basic Vue.js component that has data, method, mounted, and unmounted events in Vue 2, Vue 3, and Vue 3 with a setup script. I think you can see some different things between them and I’m going to talk about them now.

State

State or another name — data is one of the important features in Vue which support our work with our own reactive data. Let’s see how to work with the state in Vue 2 and Vue 3.

In Vue 2, the state is defined in data as a function return, an object contains our state. Here is an example:

data(){
return {
name: 'Tasy'
}
}

In Vue 3, the state will be defined in setup by ref and reactive. Here is an example:

const name = ref('Tasy');
const user = reactive({name: 'Tasy'});

Not like with Vue 2 or option API, with composition API we have two functions to make a reactive data are ref and reactive.

Lifecycle

In Vue 2, we have many lifecycle hooks and they were defined in the main object as properties. With Vue 3, we can define them inside setup as function calls. In the above, I’ve shown an example of how to define a Vue 3 lifecycle hook with onMounted and onUnmounted. For the rest of the hooks, I will show you a table of lifecycle hooks in Option API and Composition API here:

As you see, lifecycle hooks in Option API are almost the same as lifecycle hooks in Composition API. Besides names and the way to work with them, we have some other different things as well. In Vue 2, we have two lifecycle hooks which are created and beforeCreate. They were removed in Vue 3 where we can move our logic into setup. And another different thing is that we only put all of the code in one place per hook in Vue 2. In Vue 3, we can define it in many places in setup like this:

setup(){
onMounted(() => {
// mounted 1
})
onMounted(() => {
// mounted 2
})
}

Computed

computed is one of the good ways to format or handle output data and modify it in the Vue.js component. In Vue 2, we can work with computedas function in property computed of component like this:

In Vue 3, Composition API provides us with a function computed to define our computed inside of setup. We can see the example below:

Watch

Another important feature of Vue.js is watch which helps us invoke my callback when data is changed. In Vue 2, the watch was defined as almost the same with computed as an object in the Vue.js component. Different things are property name is the name of the state or prop and value of this can be function, array or string. Here is a simple component of the classic watch:

Besides the way above, we have many other ways to work with watch in Vue 2. In Vue 3, watch is almost the same with computed too. Just call it inside the setup with three parameters such as source, callback, and option (optional). If you want to define multiple handlers for data, just call watch many times. Here is a simple example of watch in Vue 3:

It’s so simple to use, I really like this. Besides that, Vue 3 provides an useful feature that is watchEffect which helps us run callback whenever the dependencies are changed. You can see an example of it here:

Components

When it comes to components, there aren’t many differences between Vue 2 and Vue 3. Just push the component we want to use into object components:

In Vue 3, we have a new way to import Component shorter with setup script:

Methods

Methods in Vue 2 are the same with computed and watch, they are defined in property methods as objects which contain our function. It will look like this:

export default {
methods: {
sayHi() {
console.log('Hi guys');
}
}
}

In Vue 3, we just need to create a function inside setup to make a method. It’s so easy:

export default {
setup() {
function sayHi() {
console.log('Hi guys');
}
}
}

There are some basic differences between Option API and Composition API.

Component Communication

I think every application also has many components and they need to communicate together to run our application. It’s very important! So Vue.js provides us with many ways to do that in both Vue.js versions. Now, let’s go back to communication in Vue 2 and learn how to do the same thing in Vue 3.

Props and Emit

The most basic way to communicate between parent and child component in Vue.js. The parent component passes values to the child component using props and the child component triggers some event in the parent component by emit . In Vue 2, we can define a props list for components in property props and use this data from this. About emit , Vue 2 provides us method this.$emit(‘eventName’, value) to emit an event to parent component with value (optional). Here is an example of a component which has a props number and can emit the event “update”:

In Vue 3, we have many ways to work with props . If you want to keep property props as Vue 2, you can get it with the first parameter of setup function. Then access its value by function toRefs or reRef. About emit, we can call it from the second parameter of setup (context) to do that job instead of this.$emit(). Here is an example of it:

Besides this way, Vue 3 provides us helpful method defineProps which supports our work with the props setup script. defineProps is called with object same with props in Vue 2 and returns a prop instance. Then we can use toRefs and toRef to access results from defineProps. About emit, Vue 3 gives us a new function defineEmits to work with emit. This function will return an instance to help us trigger the event we have defined before. Here is an example of this way:

In my opinion, I really like the second way with setup script. Please note thatdefinneProps and defineEmit are only used inside the setup script and there is no need to import them from Vue.js.

Provide and Inject

As I said above in real-life projects where we have many components, we will have a large component tree. It created the problem of Prop Drilling. To help us deal with this problem, Vue.js provides a feature called Provide and Inject. It allows us to provide data to a component’s descendants. Here is example of this:

In the root component, just need to define provide property (it’s almost the same with data) as a function that returns an object. In the component’s descendants, we just need to define inject property with the value of an array with the name we want to use from the root component. If you want to make provide and inject became reactive data, I think we can apply computed to do that job:

In Vue 3, we can use the function provide and injectinside of setup function. It is simple and easy to use:

Slots

This is a way to put parents’ views somewhere inside another component view. For slots, the two versions are basically the same. Here is an example of the two versions:

We just have a little change between them which is the property $slots . In Vue 2, this property returns objects with keys as the name of the slot and values as an array of VNode. In Vue 3, this property returns the same object with the key as the name of the slot but the value is a function that returns an array of VNode.

Another thing, $scopedSlots will be removed in Vue 3.

Code reusability

In Vue, we have many ways to reuse our code (Global property, Plugin, Extend, Mixins, etc.). Vue 3 also covers those methods and makes some optimizations for them.

Global property

In Vue 2, if we want to make some global property, we can access to propertyprototype of Vue.js like this:

Vue.prototype.$axios = axios({});

This way above is not allowed in Vue 3. If we want to make a global property, Vue 3 provides us with another way to propertyglobalProperties from property config of Vue.js App instance. Let’s see a simple example:

const app = createApp({});
app.config.globalProperties.$axios = axios({})

Mixins and custom hooks

Mixins is a flexible way to support us when we want to reuse our code, logic… for many components. It gives us a tool to apply our data, methods, or some logic in every component we want to. Here is an example of mixins:

In this example, we have created mixins with data of a number and a method to increase value of this number. If we want to implement that logic, we just need to add these mixins into the component’s mixins array. After that, your component will have that data and method. I know this is a useful way to reuse code in Vue.js and I applied it in many projects. But If mixins are abused or used heavily, we may get some problems with a truck of data, method, etc.

In Vue 3, we have another way to do that job with more clarity. This is custom hooks. In custom hooks, we can package our logic and just export what we want. Here is an example of custom hook which does the same job as with the case above:

I really like this way and I think it will be our good friend in Vue 3 projects. By the way, I have an article about ‘How to Write 10 Useful Vue.js Custom Hooks’ here:

Model

Model is one of the awesome Vue.js features which helps us work with two way data binding. In this part, I will talk about model with HTML input element and model with custom component. Let’s go.

HTML Input Element

For the input component, if you want to bind a state with an input element, you just need to use v-model with value as the name of this state. It’s the same for the two versions.

Vue 2:

Vue 3:

Custom component

For a custom component, we have many updates in Vue 3 which make this feature more flexible. Before talking about this, we will get back to Vue 2 to know how to make a model for a custom component. To do this, we need to mix props and model a bit. Here is my example:

I will explain a bit for this example. In custom input component, I’ve defined property model with value as an object which have two properties prop and event. prop is prop name you want to v-model bind (default value of this property is “value”). event is event name you need to emit to the parent component that the data have changed (default value of this property is “input”). It is important to define the props name for your model (“value” in case you want to use default model values).

In Vue 3, besides binding one model, we can bind multiple models per custom component. Basically, the way to the that is almost the same with Vue 2, just have some changes. Firstly, default prop name of v-model change from “value” to “modelValue”. Second, emit event name will be set with rule update:<model name> (example: update:title ). For binding to sub model of component, we will type with this rule v-model:<name>. Here is my example about components that have a textbox and a checkbox, v-model for textbox data and v-model:checked for the checked status of the check box:

I think there’s no need to explain more for this example because it is almost the same concept as the Vue 2 example. Just change a little syntax and follow the rule name as I said above. Then we have a custom component which can work with multiple models. For those who like to work with setup script, here is an example where we build the above component:

Above are two examples of working with model in Vue 3.

Conclusion

In this article, I’ve shared a bit about the new features of Vue 3 by going back to Vue 2. Personally, I really like this way of learning new features. There are some my reasons:

  • Taking ourselves back to the old version can make sure we don’t miss anything from the old version. As for me, I learned about v-model in Vue.js while writing this article. I haven’t used this feature before.
  • One of the best ways to know what’s improved in the new version is to go back to the old version.
  • Comparing code in the old and new version can help us understand it faster. Personally, I think syntax in the new version is often shorter than in old versions. So some code lines in the new version may be many lines (steps) in the old version. Reading code in old version can make us know what the code does in the new version.

These are the things I wanted to share today. I hope this article will be helpful for you. Read more in Vue 3 and Vue 2 documentation:

Photo by Thái An on Unsplash

Thank you for reading.

Connect with me via Linkedin or Twitter.

More content at PlainEnglish.io. Sign up for our free weekly newsletter. Follow us on Twitter and LinkedIn. Join our community Discord.

--

--