How to migrate from Vue 2 to Vue 3?
Published: 2021-07-06 15:32:27

##Introduction

As we know, the official release of Vue 3 was on September 18, 2020, it’s been almost a year, and I think it’s time to move on to it. Buuuut… it’s not that simple.

At the moment, not all plugins are adapted to Vue 3, so you have to look for replacements. I tried it and you know, it didn’t work.

But to our great luck, there is a plugin that has the same API as Vue 3. It was kindly provided by the developers themselves to soften the transition from version 2 to version 3. The plugin is called @vue/composition-api. Today we will talk about it.

##What to expect from this article

Important: This article is an introductory one with which I plan to start a series of articles on VUE 3. So, today I will show you just a few simple examples that will help whet your appetite and smoothly start your transition to the new version of Vue.

Let’s get started!

[![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1d7ac7sl228xo2hfmr0t.png)](https://maddevs.io/blog/vue-form-validation/?utm_source=devto&utm_medium=migrate-vue-3)

##Installing @vue/composition-api

First, we need to update the packages. To do this, open a terminal and use the command:

```javascript
vue upgrade
```

But note that you must have Vue CLI and Node.js installed.

After running the command, you should see a list of packages that need to be updated. If the packages are updated, the message below will appear

```javascript
DONE  Seems all plugins are up to date. Good work!
``` 

Install the Vue Composition api plugin

```javascript
yarn add @vue/composition-api// ornpm i @vue/composition-api
```

After that, create a file in the scr folder where @vue/composition-api will be initialized. Let’s call it installCompositionApi.js and add the code

```javascript
import Vue from 'vue'
import VueCompositionApi from 
'@vue/composition-api'Vue.use(VueCompositionApi)
```

This file must be imported into the main.js file, and the import function must be placed first in order for the scripts to initialize properly.

```javascript
1 // INIT COMPOSITION API(VUE 3) 
2 import '@/installCompositionApi.js' 
3 
4 import Vue from 'vue' 
5 import router from '@/router' 
6 ... 
7 ...
```

This concludes the installation of @vue/composition-api. The library is available globally and can be used in any of the files.

##Rewriting the Vuex store

The next step is to start rewriting the existing code. I would start with the Vuex store. Let’s do that. Let’s take one of the files, for example, the module responsible for the list of articles.

```javascript
import { getArticles } from '@/api/articles'

export default {
  namespaced: true,

  state: () => ({
    articles: [],
  }),

  mutations: {
    SET_ARTICLES(state, articles) {
      state.articles = articles
    },
  },

  actions: {
    async getAllArticles({ commit }) {
      try {

        const articles = await getArticles()
        commit('SET_ARTICLES', articles)
      } catch (error) {
        commit('SET_ARTICLES', [])
      } 
    }, 
  },
 }
```

You have to agree it’s pretty wordy. We have to write an additional layer in the form of mutations, actions to write data asynchronously. But come on.

We delete everything without remorse and add this code:

```javascript
// @/modules/articles
import { ref } from '@vue/composition-api'
import { getArticles } from '@/api/articles'

const articles = ref([])

const useArticles = () => {
  const getAllArticles = async () => {
    articles.value = await getArticles()
  } 
  return { articles, getAllArticles }
}

export default useArticles
```

The number of lines is reduced, and that is already good. Let’s sort it out.

The first line imports the method **ref**. It adds reactivity for any variable.

**ref** takes an argument and returns it wrapped in an object with the property **value**, which can then be used to access or change the value of the reactive variable.

In the code above, **ref** has been added for the **articles** variable, it is now reactive and has additional properties.

Then we see a function that gets all articles by API and writes them into the articles variable.

But please note that it writes them to the reactive **value** property. If it doesn’t, the value won’t change.

That’s all. Our updated **store** works in exactly the same way and is even much simpler.

*The only question that remains is whether Vuex is needed now?*

[![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i1alm0ytbqd0ds9ipsk3.png)](https://maddevs.io/blog/how-to-set-up-automated-integration-tests-in-a-vue-application/?utm_source=devto&utm_medium=migrate-vue-3)

##Rewriting the component

After updating the code in our store, let’s rewrite the component that is responsible for displaying the articles.

The component so far looks like this:

```javascript
// @/pages/articles<template>
  <div class="articles">
     <h1 class="h1">
       {{ title }}
    </h1>    // Search articles
    <input v-model="searchQuery" placeholder="Поиск" />    <template>
      <ArticlesTable :articles="articles" />
    </template>
   </div>
</template>

<script> 
import { mapState, mapActions } from 'vuex'
import ArticlesTable from '@/components/Articles/Table'

export default {
   name: 'Articles',
   components: { ArticlesTable },
   props: {
     title: {
       type: String,
       default: '',
    }
  },
  computed: {
    ...mapState('articles', {
      articles: 'articles',
    }),
  },
  async created() {
    await this.getAllArticles()
  },
  watch:
    searchQuery(query => {
      this.getAllArticles()
    },
  },
  mounted() {
    document.title = this.title

    console.log(this.$route)
  },
  methods: {
    ...mapActions('articles', ['getAllArticles']),
  },
}
</script>
```

Here we see the good old Vue 2 syntax. Let’s rewrite it to the new one, and we should get it like this:

```javascript
// @/pages/articles<template>
   <div class="articles">
     <h1 class="h1">
       {{ title }}
     </h1>    // Search articles
     <input v-model="searchQuery" placeholder="Поиск" />    <template>
       <ArticlesTable :articles="articlesList" />
     </template>
   </div>
 </template> 

<script> 
import { 
  ref, 
  computed, 
  watch, 
  onMounted 
} from '@vue/composition-api' 
import useArticles from '@/modules/articles' 
import ArticlesTable from '@/components/Articles/Table'

export default { 
  name: 'Articles',  components: { ArticlesTable },
  props: { 
    title: { 
      type: String, 
      default: '', 
    } 
  }
  setup(props, context) {
    const searchQuery = ref('') 
    const { articles, getAllArticles } = useArticles()
    const articlesList = computed(() => articles)

    onMounted(() => { 
      document.title = props.title 
       console.log(context.root.$route) 
    })
    watch(searchQuery, query => { 
      this.getAllArticles() 
    })
    getAllArticles()
    return { 
      searchQuery, 
      articlesList, 
    } 
  }, 
} 
</script>
``` 

Let me tell you right away: in @vue/composition-api and therefore in Vue 3, “**this**” is no longer available. You must use context instead. I’ll talk about it a bit later.

Let’s take apart the new rewritten component.

At the beginning of the

```javascript
attrs: (…) 
emit: (…) 
isServer: (…) 
listeners: (…) 
parent: (…) 
refs: (…) 
root: (…) 
slots: {} 
ssrContext: (…)
```

**Object this**

The global “**this**” object is now unavailable in components and we cannot use it to access, for example, the **$route** object or any other global object. To solve this, we added the property root. Now it’s the only way to access all global objects, installed plugins, etc.

**Property value**

Note, in the rewritten component, in the computed hook, we return the articles variable with the **value** property. This must be done, otherwise, the **articlesList** variable will have a reactive object, something like this:

```javascript
{_isRef: true} 
value: (...) 
_isRef: true 
get value: ƒ value() 
set value: ƒ value(newVal) 
__proto__: Object
```

In Vue 3, all reactive variables now have a **value** property.

But when using reactive variables in a template, you don’t need to call the value property as here:

```javascript
// Wrong 
<h1>{{ title.value }}</h1>
```

The object returned by the **setup()** function will be processed, and the value properties will be discarded.

```javascript
// Right 
<h1>{{ title }}</h1>
```

And in order to have access to the properties from setup in the **template** block, you have to return them with the return method.

At this point, I would like to complete the discussion. A more detailed discussion of the topic will follow in the future articles in [our blog](https://maddevs.io/blog/?utm_source=devto&utm_medium=migrate-vue-3).

##Conclusion

The process of upgrading to version 3 using the @vue/composition-api plugin was very easy because it is fully compatible with Vue 2. The syntax is uncomplicated and easy to understand. I hope you won’t have any trouble mastering it.

At this point I want to end and continue a more detailed discussion of the topics in future articles.

To learn more about the Vue Composition API, follow this [link](https://v3.vuejs.org/guide/composition-api-introduction.html#why-composition-api).

Thank you and see you soon!

[![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1gvmpsn3iz78z7epekx9.png)](https://github.com/maddevsio/vue-madboiler?utm_source=devto&utm_medium=migrate-vue-3)

*Previously published at [maddevs.io/blog](https://maddevs.io/blog/how-to-migrate-from-vue-2-to-vue-3/?utm_source=devto&utm_medium=migrate-vue-3)*.