Beginner's Guide to New Composition API in Vue 3

  • 2020-03-24 02:25 PM
  • 150

Beginner's Guide to Composition API in Vue 3 - Learn about the new Composition API in Vue 3 and how it compares to the Options API

The long-awaited Vue.js 3 is scheduled for release in the 1st quarter of 2020. The announcement of a new API, the Composition API, resulted in some controversy in the Vue community. It has since simmered down, but what is the Composition API anyway?

Although Vue 3, in its entirety, hasn’t been released yet, the Composition API is already out and ready to use. In this article, we’ll take a look at why the Composition API was introduced, how it works, and how it compares to the options-based API. At the end, we’ll build two versions of the same component: one with the Composition API and one with the options-based API!

Vue 3 Composition API vs Options API

Read Also: Building a simple Applications with Vue 3

What is the Composition API

Just to get the obvious concern out of the way, this new API will not break current Vue 2.x options-based code! We can even continue to use the Options API in Vue 3. The Composition API is just an addition to the language that was created to address the limitations of the Options API used in Vue 2. We’ll touch on those limitations in the next section.

For now, let’s talk about what it is.

Evan You, the creator of Vue, has described the Composition API as a reactive API coupled with the ability to register lifecycle hooks using globally imported functions. This is a little hard to digest, but the main point is that the Composition API provides a different way to manage reactivity at all points in an application, without compromising organization and readability.

At the root of it, the Composition API isn’t really adding anything new to the language. Instead, think about it this way: it’s exposing some of the internal functions (aka, magic) that Vue already uses, allowing us to use these functions directly in components.

Read Also: A Beginner’s Guide to Vue 3 Composition API with Examples

Why the Change?

Before we jump into the comparison, let’s look at some of the pain points in Vue 2 that the Composition API aims to solve.

Better extensibility and organization

One major concern among developers was that their Vue projects became hard to manage as they grew in size and complexity.

In Vue 2.x, components are organized using options such as data, mounted, methods, etc. Because of this, logic isn’t really grouped by feature, which can make it hard to read through a large and complex file. Readers would often have to scroll back and forth to follow what’s going on. Another downside of this organization is that it made logic reuse difficult, as features are split up unintuitively in a component.

The Composition API RFC includes this excellent diagram showing the flow of different concerns in the same component built with both the Options API and Composition API. Each color represents a different logical concern. As shown, using composition functions with the Composition API allows for better organization in components.

Vue 3 Composition API vs Options API code structure

Read Also: Getting Started With Vue 3

Better TypeScript support

The next issue with Vue 2.x was that the sometimes confusing nature of this inside components often made it difficult to use TypeScript. The Options API relies on a lot of “magic” from the Vue compiler.

The Composition API, however, uses those internal functions directly, so this behaves as expected in JavaScript. This allows for much better TypeScript support when using the Composition API.

Read Also: How to Use Vue 3 Composition API In Vue 2

Options API vs. Composition API

The best way to understand the changes is to see it in action.

Let’s build out a simple component that allows the user to add two numbers with the press of a button. First, we’ll quickly review how that would be done with the options-based API. Then we’ll rebuild that same component with the Composition API to illustrate the differences.

Vue 3 Composition API sample application

Read Also: Vue 3 - A Look At Vue-Next (Alpha) - And What You Can Do

Building with Options API

Here’s what we’ll need to create the simple addition calculator pictured above:

  • 3 variables — 1st number to add, 2nd number to add, sum
  • 2 input boxes — 1st number to add, 2nd number to add
  • A method to add the two numbers together

And here’s how it’s done in Vue 2:

<template>
    <div class="add">
        <h3>Addition Calculator</h3>
        <form id="sum">
            <input type="text" class="form-control" v-model="num1">
            <input type="text" class="form-control" v-model="num2">
            <button @click="addNumbers" type="button" class="btn btn-light">
                Add me!
            </button>
        </form>
        <p><strong>Sum:</strong> {{ sum }}</p>
    </div>
</template>
<script>
export default {
    name: 'Add',
    data() {
        return {
            num1: 0,
            num2: 0,
            sum: 0
        };
    },
    methods: {
        addNumbers: function () {
            this.sum = parseInt(this.num1) + parseInt(this.num2);
        }
    }
}
</script>
<style scoped>
    .add {
        background: #d67182;
        box-shadow: 1px 3px 6px #a3a3a3;
        padding: 50px 30px;
        width: 300px;
        text-align: center;
        margin: 80px auto;
    }
    p, h3 {
        color: #FFFFFF;
    }
    #sum {
        margin-top: 25px;
    }
    .form-control {
        margin-bottom: 15px;
    }
    .btn {
        margin-bottom: 30px;
    }
</style>

Note: We can use computed here instead of addNumbers to get the value for sum and forego the button altogether. However, we’re just going to put it into a separate method to demonstrate how functions and code structure works in the Composition API.

With the Vue 2 options-based API, we have our reactive data object returned in the data() function. Then the AddNumbers() function will be registered in the methods property. To access the variables from data(), we must use this.

Now, this is nested inside the method, so it should refer to the method’s object instead of the entire instance, but it doesn’t. Vue is working behind the scenes here to handle this for us. In general, this is pretty straightforward and intuitive, but in more complicated cases, this behind the scenes handling can cause unexpected behavior of this.

This “magic” is also part of what has made TypeScript support tough in Vue 2. Now let’s look at how this same component is built with the Vue 3 Composition API.

Read Also: Vue.js 3 Composition API Fetch With Example

Building with Composition API

To keep this short, we’ll just focus on building the component here. If you’d like to practice with the Composition API and rebuild this on your own, the Composition API can be added into a new Vue 2 project by running the following in your terminal:

vue create project-name
npm install @vue/composition-api 

Then in the main.js file:

import Vue from 'vue';
import VueCompositionApi from '@vue/composition-api';

Vue.use(VueCompositionApi);

For more information on this, check out the official Vue Composition API repo.

Now onto the final act 🎩! Let’s rebuild the addition component using the Composition API. We’re going to exclude the <style> section because nothing changes there.

<template>
    <div class="add">
        <h3>Addition Calculator</h3>
        <form id="sumComp">
            <input type="text" class="form-control" v-model="num1">
            <input type="text" class="form-control" v-model="num2">
            <button @click="addNumbers" type="button" class="btn btn-light">
            Add me!
        </button>
        </form>
        <p><strong>Sum:</strong> {{ sum }}</p>
    </div>
</template>
<script>
import { ref } from '@vue/composition-api';
export default {
    name: 'AddComposition',
    setup() {
        let num1 = ref(0);
        let num2 = ref(0);
        let sum = ref(0);
        function addNumbers() {
            sum.value = parseInt(num1.value) + parseInt(num2.value);
        }
        return {
            num1,
            num2,
            sum,
            addNumbers
        }
    }
}
</script>

First, we’re importing the functions we need to use from the Composition API at the top. In this case, that’s just ref.

Next, notice that everything is now inside a setup() function. Any functions or properties that need to be used in the template should go in setup() since this is how they’re returned to the template.

Inside setup(), the reactive variables we’re using are defined at the top as standalone variables, as opposed to a return object in the data() function.

The function addNumbers() is also hanging out on its own instead of nested in the methods property. We can now easily reuse our functions across component instances, which will significantly improve the readability of large codebases. Notice also that this is no longer needed to reference variables! Using the Composition API functions directly instead of through Vue component options removes the this magic that was occurring behind the scenes.

Finally, we’re returning the functions and properties to the template.

Read Also: Everything You Need to Know about PortalVue in Vue.JS 3.0

Reactivity: ref vs reactive

One new thing here is the use of ref in the variables, e.g., let num1 = ref(0). This is how we’re making our variables reactive! There are two functions that can be used to handle state and reactivity: ref and reactive.

ref()

ref, as shown in this example, takes a value and returns a reactive reference object. This object has a single value: .value that points to the value provided. Notice the use of .value on the variables in the addNumbers() method.

Refs can be created directly, as we’ve done here, or by using computed().

The computed() getter function will return an immutable (can’t be changed) ref object thats value can be accessed with .value(). It can also accept an object with a setter function to make it mutable if necessary.

Earlier, we mentioned that it would be better to find the sum of the numbers with computed(), but we kept it in the method for demonstration’s sake.

Here’s how it would be done using computed():

let sum = computed(() => parseInt(num1.value) + parseInt(num2.value));

Make sure to add computed to the import at the top as well:

import { computed } from '@vue/composition-api';

Note: Because computed() creates a ref, it can be used with primitive values as well. Normally the primitive value would get lost because primitives (essentially non-object values, such as a number) are passed by value, not reference. ref, however, will wrap the value and create an object. The value of the object can be referenced with ref.value. And then, when the computed() value changes, ref.value will change as well.

reactive()

The next way to handle reactivity is by using reactive. This is equivalent to Vue.observable() from Vue 2.x. It accepts an object and returns a proxy to that object that will be tracked. In this example, we’re using ref for reactivity, but we could easily use reactive instead, like so:

let state = reactive({ 
    num1: 0,
    num2: 0,
    sum: 0
})

If done this way, then addNumbers() would change to:

function addNumbers() {
    sum = parseInt(num1) + parseInt(num2);
}

This was a very simple example of a component built with the Composition API, but hopefully it has demonstrated how the new API can lead to better code organization and less “magic”.

Read Also: Vue 3 Portals Tutorial

Summary

We’ve now gone over what the Composition API is, why it was necessary, and how you can build a component using it. The Composition API is already published and ready to use, so make sure you go check it out on GitHub! Let me know below if you’ll be trying out the Composition API or sticking to the options-based API. Thanks for reading!

Suggest