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?
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
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!
Previously published at maddevs.io/blog.
Top comments (0)