Getting Started With Vue 3 Composition API
Posted on: December 06, 2019 by Afolayan
For a long time now, Vuejs has been one of the favorite frontend Javascript frameworks of many developers (including myself ) because of its reactivity and the general saying that the framework is relatively easier to pick up that most JavaScript frameworks.
As at the time of writing this article, the current version of Vuejs is 2x, with Vue3x set to be released anytime soon.
With Vue3x however, comes some amazing edges. i.e
- Smaller and Faster
- New features
- Improved support for Typescript
- Exposes lower-level APIs
- More Maintainable codebase
let app = new Vue({
data:{
// Application data stays here
},
computed:{
// computed properties stay here
},
methods:{
// application functions and methods reside here
},
watch:{
// watchers go here
}
})
The Composition API introduces a setup option for working with components and the syntax looks similar to this:
let app = new Vue({
beforeCreate(){
},
setup(){
},
created(){
}
})
The setup option looks similar to lifecycle hooks but is far more powerful.
Why the need for the composition API?
Well, the Composition API helps organize code better and improves the reuse of logic throughout the entire codebase as well as improved support for typescript. Let’s see this in more detail:Fetching an API with the Options API
The block of code below shows an example of fetching data from an API using the conventional Options API. import axios from 'axios'
import orderBy from 'lodash.orderby'
export default {
data () {
return {
characters: [],
loadingState: null,
orderKey: 'id'
}
},
computed: {
charactersOrdered() {
return orderBy(this.characters, this.orderKey)
}
},
methods: {
fetchAllCharacters () {
this.loadingState = 'loading'
axios.get('https://rickandmortyapi.com/api/character')
.then(response => {
setTimeout(() => {
this.loadingState = 'success'
this.characters = response.data.results
}, 1000)
})
},
setOrderKey(key) {
this.orderKey = key
}
},
created () {
this.fetchAllCharacters()
}
}
Fetching with the Composition API
If we use the new composition API, the code would look similar to this:import axios from 'axios'
import orderBy from 'lodash.orderby'
import {computed, ref} from '@vue/composition-api'
export default {
setup () {
const characters = ref([]) // use const because you dont want to lose this value
const loadingState = ref(null)
// Fetch Data Feature
const fetchAllCharacters = () => {
loadingState.value = 'loading'
return axios.get('https://rickandmortyapi.com/api/character')
.then(response => {
loadingState.value = 'success'
characters.value = response.data.results
})
}
// Order Fethced Data Feature
const orderKey = ref('id')
const charactersOrdered = computed(() => {
return orderBy(characters.value, orderKey.value)
})
const setOrderKey = (key) => {
orderKey.value = key
}
return {characters, loadingState, fetchAllCharacters, charactersOrdered, orderKey, setOrderKey}
},
created () {
this.fetchAllCharacters()
}
}
We see that the code above helps to organize and separate the features of our application. Let’s look at a further example of working with the composition API.
Reactivity and State with the Composition API
Another Supercool feature of Vue3 is an upgrade to its well-loved reactivity. With the Composition API being released, reactivity and state can be handled by two new methods: refs and reactive. There are two ways to deal with state and reactivity in the setup function, refs and reactive. Using one over the other is a matter of preference and coding style. They both allow Vue to keep track of your state.- Need to be imported to be used
- Data using refs or reactive need to be returned as objects from setup function
Using Refs
The code block below is an example of when to use refs:<template>
<button @click="increase">
Count is: {{ count.value }}, double is: {{ count.value * 2 }}
</button>
</template>
<script>
import { ref, watch } from 'vue'
let count = ref(0)
function increase() {
count.value++
}
const renderContext = {
count,
increment
}
watch(() => {
renderTemplate(
`<button @click="increment">8</button>`,
renderContext
)
})
</script>
Using Reactive
Working with reactive Reactive takes an object and returns a reactive objectsetup() {
Const todos = reactive({
item: ''
}) }
Computed properties can be included inside a reactive object Use the toRefs
method (creates a plain object with reactive properties) when destructuring or spreading an object return {…toRefs(todos)}
Installing and using the Composition API
Let’s understand the composition API by building a To-Do Application Currently, to use the Vue3x composition API, we need to install it separately as the Vue CLI still uses Vue2. To do this, in your project directory, open up a terminal and run:npm install @vue/composition-api
Then modify your main.js file as thus:
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')
I would want us to add some styling and icons to our application, so go ahead and open up the index.html
file in the src
folder and update it as below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%=%20BASE_URL%20%>favicon.ico">
<title>composition-todo</title>
<link rel="stylesheet" href="https://bootswatch.com/4/lux/bootstrap.min.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
<noscript>
<strong>We're sorry but composition-todo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
Next, open up your app.vue
file and update the content as thus:
<template>
<div id="app">
<section class = "container">
<div class="card">
<div class="card-header"> <h3> Add New Todo</h3></div>
<div class="card-body">
<input type="text" class = "form-control" v-model ="state.todo"/>
<button class="btn btn-primary my-2" @click="addNewTodo"> Add Todo</button>
</div>
</div>
<div class="container my-5">
<div class="card">
<div class="card-header"> <h3> MyTodos</h3></div>
<div class="card-body">
<ul class="list-group">
<li class="list-group-item" v-for="(todo, i) in state.todos" :key="i">
{{todo}} <i class="fa fa-trash" aria-hidden="true" @click="removeTodo(i)"></i>
</li>
</ul>
</div>
</div>
</div>
</section>
</div>
</template>
<script>
import { reactive } from "@vue/composition-api";
export default {
setup(){
const {state, addNewTodo, removeTodo} = useTodo();
return {
state,
addNewTodo,
removeTodo
};
}
}
function useTodo(){
let state = reactive({
todo: "",
todos: []
});
function addNewTodo(){
state.todos.push(state.todo);
state.todo = '';
}
function removeTodo(i){
state.todos.splice(i);
}
return{
state,
addNewTodo,
removeTodo
};
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.fa {
color:red;
margin-left: 20px;
/* height: 40px; */
}
.fa:hover{
color: black;
/* height: 50px; */
}
</style>
You can serve your application with
npm run serve
Conclusion:
In conclusion, while the Vue 3 composition API seems to be a much better way of working with components, it is important to note that the Composition API is only an alternative to the current Options API and not an overhaul. We can still work with components using options, mixins and scoped slots as it was before as the Vue core team has said the Options API would still be supported. You can find the source code of our application on its GitHub repository here.Share on social media
//