Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.
In this article, we’ll take a look at the Vue Composition API plugin for Vue 2.x to create our components in ways that are closer to the Vue 3.x way.
Vue Composition API
The Vue Composition API lets us move reusable code into composition functions, which any component can use with the setup
component option.
With it, we don’t have to worry about name clashes between mixin members and component members because all the members are encapsulated in their own function and we can import them with new names.
Also, we don’t have to recreate component instances to reuse logic from different components.
The Composition API is built with large projects in mind, where there’re lots of reusable code.
In addition to the benefits that are listed above, we also have better type inference. It’s also more readable because we can trace all the code back to their composition function where the code is declared in the setup
method.
The Vetur VS Code extension, which helps with developing Vue apps with VS Code, provides type inference when it’s used with the Composition API.
How to Use It?
With Vue 2.x projects, we can use it by installing the Vue Composition API package as follows for Vue CLI projects:
npm install @vue/composition-api
It’s also available for projects that don’t use the Vue CLI as a library that we can add via a script tag as follows:
<script src="https://unpkg.com/@vue/composition-api/dist/vue-composition-api.umd.js"></script>
The rest of the steps assumes that we’re building a Vue CLI project.
Once we installed it, we can use it by first registering the plugin as follows in main.js
:
import Vue from "vue";
import App from "./App.vue";
import VueCompositionApi from "@vue/composition-api";
Vue.use(VueCompositionApi);
Vue.config.productionTip = false;
new Vue({
render: h => h(App)
}).$mount("#app");
Next, we’ll actually use the Vue Composition API plugin to build our components.
First, we create a file called Search.vue
in the components
folder as follows:
<template>
<div class="hello">
<form @submit.prevent="handleSubmit">
<label>{{label}}</label>
<input type="text" v-model="state.name">
<input type="submit" value="search">
</form>
</div>
</template>
<script>
import { reactive } from "@vue/composition-api";
export default {
name: "Search",
props: {
label: String
},
setup({ label }, { emit }) {
const state = reactive({
name: ""
});
return {
handleSubmit(event) {
emit("search", state.name);
},
state
};
}
};
</script>
In the code above, we have created a component that takes a prop called label
, which is a string.
Then we can get the value of the prop by getting it from the first argument of the setup
method instead of getting the prop as a property of this
with the original Vue API.
Also, the emit
method is retrieved from the object that’s passed into setup
as the 2nd argument of it instead of a property of this
.
To hold states, we call the reactive
function from the Composition API package by passing in an object with the state properties to it.
state
and reactive
are equivalent to the object that we return in the data
method with the regular Vue API.
The state
constant is return as a property of the object so that we can reference the states as properties of state
in our template.
To add methods with the Vue Composition API, we add them to the object that we return instead of as a property of the methods
property like we did without the Vue Composition API.
We did that with the handleSubmit
method.
In our template, we bind v-model
to state.name
rather than just name
. But we reference the handleSubmit
method like we do with methods before.
The search
event is emitted when we type in something to the input and the click search.
Next, in App.vue
, we write the following code:
<template>
<div id="app">
<Search label="name" @search="search"/>
<div>{{state.data.name}}</div>
</div>
</template>
<script>
import Search from "./components/Search";
import { reactive } from "@vue/composition-api";
export default {
name: "App",
components: {
Search
},
setup() {
const state = reactive({
data: {}
});
return {
state,
async search(ev) {
const res = await fetch(`https://api.agify.io/?name=${ev}`);
state.data = await res.json();
}
};
}
};
</script>
In the code above, we have similar structure as in Search.vue
. Something that we didn’t have in this file is listening to events.
We have the search
method which listens to the search
event emitted from Search.vue
. In the search
method, we get some data, assign it to the state
, and display it on the template.
Also, we assigned the retrieved data to state.data
instead.
We can add computed properties with the computed
function from the Vue Composition API package.
For instance, we can replace App.vue
with the following to create a computed property and use it:
<template>
<div id="app">
<Search label="name" @search="search"/>
<div>{{state.name}}</div>
</div>
</template>
<script>
import Search from "./components/Search";
import { computed, reactive } from "@vue/composition-api";
export default {
name: "App",
components: {
Search
},
setup() {
const state = reactive({
data: {},
name: computed(() =>
state.data.name ? `The name is: ${state.data.name}` : ""
)
});
return {
state,
async search(ev) {
const res = await fetch(`https://api.agify.io/?name=${ev}`);
state.data = await res.json();
}
};
}
};
</script>
In the code above, we changed App.vue
slightly by importing the computed
function to create a computed property.
To create the property, we added:
computed(() => state.data.name ? `The name is: ${state.data.name}` : "")
Then in the template, we referenced it by writing:
<div>{{state.name}}</div>
Now when we type in something and clicked search, we get ‘The name is (whatever you typed in)’ displayed.
Conclusion
The Vue Composition API is useful for creating components in a complex app. It’s organized that reduces clashes of names and provides better type inference in our components.
We still have everything that we’re used to like states, methods, events, templates and computed properties. It’s just that they’re in different places.