Almost a year ago, Evan You, creator of Vue, presented a preview at VueConf of what will be Vue 3, whose main pillars are:
- Faster
- Smaller
- More maintainable code
- Friendlier with native environments (Android, iOS, Desktop, etc.)
- Easier to use
One of the new features it will bring is what was called Hooks API at the time (inspired by React Hooks), and has since been renamed to Composition API.
This new API allows us to simplify components and make code reuse easier; it will especially impact medium and large components as it allows extracting parts of the logic easily into several files, reusing it, and organizing the code better by logical concepts instead of options. Currently, in Vue 2.x, we have to organize a component’s code by options, in the following way:
export default {
name: 'component-name',
props: {
...
},
components: {
},
data () {
return { ... }
},
computed: {
....
},
watch () {
....
},
methods: {
....
},
mounted () {
}
....
}
In components of a certain complexity, this causes variables and the methods that manage them to be separated, for example.
Let’s look at a simple example of what I mean: a component that shows what we type in an input, displays it in uppercase, and also has a button to add an emoji:
If you notice, we have the text variable on one side, the uppercase computed variable on another, and the addEmoji method on another. In this component, they are all quite “close,” but if we keep adding methods and variables, they start to drift apart.
With Composition API, we can keep all these elements “close” by logic or functionality (this is shown very graphically in the video I linked at the end).
Before continuing, we should know that in Vue 2.x, to use the Composition API, we need to install the vue/composition-api package with a simple:
yarn add @vue/composition-api
Once this is done, we refactor the component as follows:
Nothing significant has changed in the <template>, so let’s go to the javascript, which is where the “meat” is.
First, we see an import that brings us: reactive, computed, and ref; we’ll see what each one is in a moment.
Next, we see a setup() method, none of the “traditional” options (data, methods, computed, etc.), and this is where we’ll perform the composition API magic. Instead of having an option in the object for each thing: data, computed, methods, we define them directly in the setup() method and return them. Let’s go step by step:
const text = ref('');
Vue needs the reactive element to be passed by reference, which javascript doesn’t do with primitive types like in this case (a String). For this, Composition API provides us with ref().
In case we used an object that we wanted to be reactive, we would use reactive:
const state = reactive({
text: '',
});
The next thing we find is the computed variable:
const uppercase = computed(() => text.value.toUpperCase());
Simple: we use computed, pass it the computed function, and transform the value of the text variable to uppercase.
Here we can already see a couple of details:
- The
.value: this is becauserefconverts the primitive type into a plain object, storing the actual value in thevalueproperty. Note that in templates, it is not necessary to use.valueas ref unwrapping is performed. - Another important detail is where is this? Well, basically it isn’t there.
setup()is called before mounting the component, so in that context, this doesn’t work as we knew it.
A bit further down, we have what was previously the addEmoji method, which is now a function:
function addEmoji() {
text.value += '😂';
}
And finally, we return all the elements we are going to use:
return {
text,
uppercase,
addEmoji,
};
At first glance, it all seems a bit more complicated and cumbersome, and it surely is for small components, but as soon as the component starts to grow, this allows us to group the logic of each part of the component instead of having it separated in different object properties. Additionally, it simplifies extracting both reactive and computed variables, as well as methods, to an external file:
import compositionFunction from './demoCompositionApi.js';
export default {
setup() {
return {
...compositionFunction(),
};
},
};
It’s worth noting that the traditional method will still be available and there are no long-term plans to remove it, so we can use one development method or the other. This is something Evan You made very clear after the so-called “Vue Darkest Day”, where, with the announcement of the Composition API, the community interpreted that the “traditional” system would be removed, generating quite a bit of controversy.
I recommend watching this video to understand the advantages of the Composition API in a very graphic way:
Also, check the Composition API RFC.
I’ll leave the demo project on codesandbox:
Sergio Carracedo