(Partially) Different Way to Build Component using Vue Composition API

Gusti Raditia Madya
6 min readNov 19, 2020

In September 2020, Vue.js released their latest version, Vue 3, which gave us quite a lot of changes. Yet in this article, I will focus on one of the significant changes, namely the Vue Composition API. But before that, here’s a summary of some of the updates to Vue 3 and why we should give it a try.

Why Vue 3?

  • Smaller + faster
  • Improved Typescript support
  • Composition API
  • Multiple root nodes on template (we can only have one root on Vue 2)
  • Multiple v-model on components
  • Suspense
    component that renders fallback content instead of your component until a condition is met such as a loaded backend API
  • Portal
    allows you to display blocks of code anywhere in the app (modals, notifications, etc)
  • Provide/Inject

Vue Composition API

In Vue 2, we know about the Option API model that we have used frequently in creating Vue components. Then what is the Composition API? In short, all the reactive data, computed, watch, methods we use in the Option API are now wrapped inside a setup() function..

The Composition API is an alternative way of writing the logic behind our components. And it was introduced because we might face two main limitations or issues when building bigger Vue apps. In smaller and medium-sized apps, we will very likely never face those issues, but in bigger apps, we might face them. One of the issue is that the code that belongs together logically is actually split up across multiple options, data, methods, computed. Second issue is that re-using logic across components could be tricky and cumbersome.

ref

import { ref } from 'vue'

ref is used to create reactive properties such as to keep track of user input, or to create reactive variables or objects. ref is a wrapper object where the value of our property is stored in another property called .value. So, if we want to call our properties we should access it by typing propertyName.value

ref vs reactive

Apart from ref, we can also use reactive() to create a reactive property. We can use ref when the variables we create are in the form of strings, numbers, Boolean, etc. When dealing with objects, I recommend using reactive(). If we use ref, it will wrap our value inside the object .value. reactive() doesn’t wrap our object with values so we can immediately access it.

watchers

In Vue 2 we can only define one dependency if we use optional API, now we can define multiple watchers which return array. Here is the differences in how we define watchers in Vue 2 and Vue 3

Props with composition API

In Vue Option API, we could access props by typing this.propsName . But in Vue Composition API, we use props as a parameter inside the setup() method.

Emitting Custom Events using Context

There are cases when we need to emit data from child to parent. In Vue 2 we are familiar with using this.$emit(‘emitName’, data). But we can’t do this method in Vue 3, since we don’t have access to this in setup(). Thus, to emit events, we need to use a context object.
Context is the second parameter of setup(). When we try to see the contents of the context by doing console.log() there are 3 properties, namely attrs, emit, and slots. attrs are any fall through attributes you might have. slots gives you access top any slot data you might have in your component. emit is a function you can call to emit a custom event

Provide/Inject

We can use props when passing data from parent to child. Of course, it will be very easy if we pass data to a child that is only one level below the parent. But what if the component structure is like this?

We could either make child 1 receive props from the parent then pass the props data to child 2 or use state management. The first option seems to be inefficient since we add props in child 1 just to pass the data to the next children component — child 1 has nothing to do with the data. But there is another approach offered by Vue, namely by using Provide / Inject.

Provide / Inject is a capability where parent components can serve as dependency provider for all its children, regardless how deep the component hierarchy is.

It actually possible if you want to update the ref value in the child component but it is not recommended. You should always change injected values in the place where you provide them

To add reactivity between provided and injected values, we can use a ref or reactive when providing a value.

To ensure the data passed through cannot be mutated by the injected component, we can use readonly() when passing the data.

provide ('name', readonly(name))

Lifecycle Hooks

In Vue 2, we have, beforeCreate and created in the options API, and we could simply add those methods to our config object. How does this look like with the composition API? With the composition API, we don’t add those lifecycle hooks to our component config object anymore, instead we have functions which we can import from vue, which you can call inside of the setup() method. But for beforeCreate and created there actually is no equivalent, because these hooks are not needed here, because the setup() method basically runs at the same time beforeCreate and created ran in the past. So setup() replaces these hooks. Whatever you would have done in created or beforeCreate should be done in the setup() method itself. Now for beforeMount and mounted, it’s different. There we have the onBeforeMount and onMounted functions which can be imported from vue. For beforeUpdate and updated it’s similar and the same for beforeUnmount and unmounted.

Vuex 4.0

Vue 3 also changed the way we access the store since we don’t have access to this.$store in setup hook. To access the store within the setup hook, you can call the useStore function. This is the equivalent of retrieving this.$store within a component using the Option API.

To access the state and getters, we have to create computed references to retain reactivity, and to access mutation and action we could just simply use the commit() and dispatch() like we used to do in Vue 2.

We usually use mapGetters and mapActions in our components with the Options API. In Composition API we could use vuex-composition-helper by installing this package

First we import the useGetters and useActions, and then we create a constant which the name is the getter/action name — using object destructuring, and the last we expose the constant into our template. This way is easier to use when we are dealing with modules. So for example, if the incrementCounter is inside the counter modules, we could write it like this

const { incrementCounter } = 
useActions('counter',['incrementCounter'])

Summary

Here are the brief differences between Option API and Composition API

We no longer use data(), instead we use ref() and reactive() to create reactive properties. We don’t define methods but create and regular javascript function inside the setup() hook and then expose it to the template. We could have multiple watchers that return an array, and a lot more. You can find the complete documentation about Vue 3 and Vue Composition API here.

--

--

No responses yet