Vue 3 Composition API

Getting Started With Vue 3 Composition API


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
One of the features Vue3x is bringing is the Vue 3 Composition API which is a differentiation from the traditional Vue2 Options API. Traditionally with the Options API, the way to initialize an instance of Vue will be similar to the code block below:
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
It is important to have it in mind that knowing when to use refs and reactive, can be confusing and best practices are still being developed

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 object
setup() {
 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
Vue 3 Composition API
todo app vue 3 composition API

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

//