Getting Started with the Vue 3 Composition API
Vue 3 is here. One of the biggest features in Vue 3’s release is Vue’s new Composition API. As developers begin building more large-scale projects with Vue, some of the underlying challenges of code organization, readability, and reusability have become more apparent.
The goal of the Composition API, which is inspired by React Hooks, is to simplify your components, improving readability and organization, and make it easier to reuse code throughout your application.
The Composition API will not only allow developers to use it over component options, but it also adds in composition functions, which can be used over Vue’s other methods of code reusability (e.g., mixins and scoped slots). In this article, we’ll outline the drawbacks that Vue 2 had in terms of reusability, readability and organization, and highlight the ways that the Composition API addresses those issues.
Wijmo’s Vue 3 Plans: The Wijmo team is working hard to make sure that Wijmo’s controls are ready for Vue 3 on launch. Wijmo is dedicated to providing powerful components, such as FlexGrid, to help Vue developers build their applications with ease.
Installing the Composition API
Though the Composition API is a part of Vue 3, it has been made available for Vue 2 as well. You can add the Composition API to your project by running the following command:
npm install @vue/composition-api --save
Then, you’ll import the file inside of your main.js file:
import VueCompositionAPI from “@vue/compostion-api”;
Vue.use(VueCompositionAPI);
Your project will now be able to utilize Vue 3’s Composition API.
Code Organization and Readability
In Vue 2, features of components were organized using component options. These options include things like data, method, etc.; in total, there are six component options, meaning that your component’s logic can be split across up to six sections of your component.
As your components grow, this fracturing of code within the components will not only make them harder to organize, but it will also make it harder for other developers that are reading through the code to understand the flow of logic within the component.
Vue 3’s Composition API gets rid of component options and replaces them with its setup() function. The setup() function gives developers more control over how they organize their code base, allowing it to be organized by logic and functionality instead of being restricted by the component options.
<template>
<div>
<h1>Counter</h1>
<p>Count: {{ count }}</p>
<button @click="countIncrement()">Increase Count</button>
<button @click="countByFive()">Increase Count by 5</button>
<button @click="clearCount()">Clear Count</button>
</div>
</template>
<script>
export default {
data: function() {
return {
count: 0
}
},
methods: {
countIncrement() {
this.count++;
},
clearCount() {
this.count = 0;
},
countByFive() {
this.count += 5;
}
}
}
</script>
As we see above, with just a few methods, this doesn’t look too bad. But as we add more functionality to the component, the logic will become more and more fragmented across the component options.
<template>
<div>
<h1>Counter</h1>
<p>Count: {{ count }}</p>
<button @click="countIncrement()">Increase Count</button>
<button @click="countByFive()">Increase Count by 5</button>
<button @click="clearCount()">Clear Count</button>
</div>
</template>
<script>
import { ref } from "@vue/composition-api";
export default {
setup() {
const count = ref(0);
function countIncrement() {
this.count++;
}
function clearCount() {
this.count = 0;
}
function countByFive() {
this.count += 5;
}
return { count, countIncrement, clearCount, counyByFive ; }
}
</script>
With the Composition API, we ditch component options and replace them with the setup() method. Now you’re able to structure your components in ways that best fit your logic and functionality, instead of being restricted by the component options.
This will make it easier for both you as well as other developers to read the code and understand the logic behind the component. This is especially useful as components grow larger and encompass more logic.
Developers are not required to use the Composition API, either; Vue 3 continues to support component options. If you’re more comfortable using the component options model, you’ll be able to use Vue 3 while maintaining the same component structure.
Code Reusability
The Composition API aims to tackle another issue that Vue 2 had: code reusability. Two ways that Vue 2 allowed you to reuse code was through mixins and scoped slots. However, both methods have drawbacks.
Mixins
Mixins are designed to let components share properties and methods between one another. Say we want to share the properties and methods of our base counter with another counter. We would need to create a mixin of our base counter that can be consumed by the new counter.
const counterMixin = {
data: function() {
return {
count: 0
}
},
methods: {
countIncrement() {
this.count++;
},
clearCount() {
this.count = 0;
},
countByFive() {
this.count += 5;
},
}
}
export default {
mixins: [counterMixin]
}
Here, we create our mixin and allow it to be exported. It can then be imported to any component that needs to consume it by adding it to the mixin configuration property. However, one of the issues that mixins have is that they are prone to conflict.
If a property name in the mixin matches a property name of the component consuming it, the component will prioritize keeping the value of its property and will discard the property of the mixin.
Mixins also lack flexibility; the methods are restricted to their base functionality and cannot be configured to function based on the needs of the component consuming it.
Scoped Slots
Vue 2 also offered scoped slots as a way for developers to reuse code. While standard slots allowed you to pass a rendered element, scoped slots allowed you to create custom templates, which the scoped slots then consume to render the template in the parent element.
Here, we’ll show how to display users’ names along with their associated count value:
<template>
<div>
<slot v-for="item in items" :item="item">
<!-- fallback content here -->
</slot>
</div>
</template>
<script>
export default {
props: {
items: {
type: Array,
default: () => []
}
}
};
</script>
This template binds the items attribute to the slot element, making it available to the parent element. That will allow us to modify this template when it is consumed.
Here, we have no fallback content when data isn’t provided to the template; typically, you’ll have something set up to display some fallback data.
<template>
<div id="app">
<div class="list-title">Counter List</div>
<List :items="listItems">
<div slot-scope="row" class="list-item1">
<span>Name:</span>{{row.item.name}}<span>Count:</span>{{row.item.count}}
</div>
</List>
</div>
</div>
</template>
<script>
import List from "./components/List.vue";
export default {
components: {
List
},
data() {
return {
listItems: [
{ name: "Bill", count: "6" },
{ name: "Susan", count: "13" },
{ name: "Jim", count: "2" },
]
};
}
};
</script>
You can see how we can use scoped slots to render templates, as well as modify the templates to render the content that we need to display. While this addresses some of the issues that mixins had regarding flexibility, scoped slots still have their own limitations.
With more complex templates comes more indentation, which makes code less readable, and scoped slots also require a lot of configurations to be set up. Scoped slots also break up code across multiple components, which means that there is a performance cost as well.
Composition Functions
Vue 3’s Composition API brings composition functions to the table as another way of tackling code reusability. Composition functions accept configurations, making them easy to customize and use across multiple components.
First, we need to define the composition functions that we will use. In this case, we’ll create generic count increment and count reset methods:
export default function useIncrement({ increment }) {}
export default function useReset({ value }) {}
We’ll then need to import these functions into our component. After importing them, we can pass them the configurations that we want to use for them, and then give our component access to these functions by returning them in our setup() method:
<script>
import { ref } from "@vue/composition-api";
import useIncrement from "./components/countIncrements";
import useReset from "./components/countReset";
export default {
setup() {
const count = ref(0);
const countIncrement = useIncrement( /* configurations */ );
const countReset = useReset( /* configurations */ );
return { count, countIncrement, countReset }; }
}
</script>
By setting up these composition functions, we can now use them across our application, and customize them to fit our needs. Maybe we don’t want the counter to reset to 0, and instead reset to 10; we would just need to pass a different value into the function’s configuration, and it will now behave as needed.
Composition functions cut out a lot of excess code, allowing for more readable code. Configurations allow you to customize them across your application, making your code more reusable; and because they are functions, they are supported by Intellisense.
Closing Notes
The Composition API aims to address both code reusability and code readability in Vue 3. By replacing component options with the API’s setup() method, the Composition API allows developers to organize their components by logic and functionality, instead of being restricted by organizing it through component options.
Composition functions allow us to create easily reusable functions, which can accept configurations that customize it to fit the needs of the component consuming it.