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!

Installing @vue/composition-api

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

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

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

Install the Vue Composition api plugin

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

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.

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.

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:

// @/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.

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:

// @/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:

// @/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 <script> block the hooks are imported. Yes, now you have to import them to use them.

Below, note the setup method, it is the entry point where all the magic of reactivity happens. It has two arguments:

  1. props: through it we get props, which are passed to the component
  2. context: this is exactly what replaces “this”. Through it, you can access the emit method, the slot variable, attrs, etc. Here is the complete list.
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:

{_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:

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

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

// 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.

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.

Thank you and see you soon!

Vue Boilerplate.
How to configure Apollo GraphQL in Nuxt application.

How to Configure Apollo GraphQL in Nuxt Application

How to Configure Apollo GraphQL in...

How to Configure Apollo GraphQL in Nuxt Application

Good time of the day, friends!Today I want to show you how to set up Apollo GraphQl in a Nuxt application, where nuxt will take care of both client...

How to Configure SSG and SSR on Nuxt.

How to Configure SSG and SSR on Nuxt

How to Configure SSG and SSR on Nuxt

How to Configure SSG and SSR on Nuxt

When I started learning Vue, I was pleasantly surprised by this framework. It turned out to be very simple and easy to learn. Its API had enough...

Strapi - Things to Keep in Mind Before Migrating to This CMS

Strapi: Things to Keep in Mind Before Migrating to...

Strapi: Things to Keep in Mind Before...

Strapi: Things to Keep in Mind Before Migrating to This CMS

When it comes to CMS, the modern market has already stepped so much that the choice is becoming increasingly difficult. There are so many options for...