In September 2020, Vue.js released its version 3 series.
The most notable feature of the version 3 series is arguably the introduction of the “Composition API.”
The Composition API is a new format for Vue components, and its implementation and syntax differ significantly from the Options API format, which was the standard in the version 2 series.
In this article, the editorial team of Skilled, a front-end specialized programming learning tool, will clearly explain what the Composition API is and how it differs from the Options API.
目次
What is the Composition API?
The Composition API is a format for components that allows you to separate and handle reactive values and processes related to those values from the component itself.
With the Composition API, you can create components using imported functions.
Understanding the features of the Composition API is easier when looking at the issues with the Options API format, which was the traditional component format in Vue.js.
We will look at the issues with the Options API and compare
Problems with the Options API (Traditional Vue)
Below is the script block for a counter app written in the Options API.
export default {
data: () => ({
count: 0,
}),
methods: {
add() {
this.count++;
},
reduce() {
this.count--;
},
doubleUp() {
this.count = this.count * 2;
},
reset() {
this.count = 0;
},
},
};
If you have used Vue.js before, you’ll find this script block familiar.
The issues with this Options API format include:
- You have to go through ‘this’ to access reactive values, making it impossible to separate the processing in ‘methods’ from the Component’s View.
- Related elements become scattered.
There are often times when you want to separate and reuse the logic in the ‘methods’ section, but if you are accessing reactive values, you generally can’t separate it from the view. This was a problem with the Options API.
Because you can’t separate it, when you create complex components, you end up with a bloated structure where just the script block alone can be several hundred lines long.
Another issue is that related elements become scattered.
For example, let’s say an element called ‘member’ is added to the above code, and computed properties for adding, deleting, and sorting members are also added.
In the Options API, you add elements to each option property like data, methods, and computed.
As a result, it’s difficult to group related elements together. The structure becomes scattered as shown below, and as the component becomes more complex, readability suffers.
Drawbacks of Mixins
In the Options API, you can use the mixin feature to bundle and reuse elements like data and methods.
However, there are several drawbacks to using mixins:
- Ambiguous Elements: When using multiple mixins, it becomes unclear which instances within the component are added by the mixins.
➝ In the Composition API, reactive values are managed independently of the view through refs, making the source of properties clear. - Namespace Conflicts: When using multiple mixins, there’s a possibility of registering duplicate property keys.
➝ In the Composition API, if there are conflicting keys, you can change the name of the destructured variables. - Mixin’s ‘this’ is not Loosely Coupled: The ‘this’ in mixins refers to the component, making it not loosely coupled. You need to design with the component dependencies in mind.
These drawbacks are also mentioned in the official documentation, and the use of mixins is discouraged from Vue 3 onwards.
Solving with the Composition API
Next, let’s write the script block with the same behavior using the Composition API.
The Composition API has a feature called Composition Functions.
This feature allows you to extract the component’s logic without depending on the View.
Using this feature, you can separate the elements used in the counter and the elements used in the member, and define them in separate files.
As shown above, encapsulating stateful logic using the Composition API is called “Composable.”
Composables can be easily invoked by importing them.
The component called from App.vue by importing it will look like this.
Compared to the Options API, you can describe the elements of logic without scattering them.
One of the features of the Composition API is that by dividing and managing elements, you can create components with high readability without scattering related elements.
How to Use the Composition API
Here, we will explain how to use the Composition API while comparing it with the Options API.
We will introduce how to rewrite it compared to the properties of the Options API.
data
Options API
data: () => ({
count: 0,
}),
Composition API
import { ref } from "vue"
const count = ref(0);
In the Options API, reactive values were defined using the data option, but in the Composition API, you define and use the ref and reactive functions.
There are the following differences between ref and reactive:
- ref ➝ Directly accessible (for primitive types)
- reactive ➝ Accessed like an object using a “.” (dot)
methods
Options API
methods: {
addCounter() {
this.count++;
},
},
Composition API
const addCounter = () => {
count.value++;
};
In the Options API, you defined them within the methods option, but in the Composition API, you can simply define functions within the script block to call them.
A significant change is the specification for modifying reactive values.
To change a reactive value defined with ref, you use `.value`.
count.value++;
In this example, we are changing the value of the `count` variable by accessing and modifying its `value`.
computed
When using `computed`, you define it using the `computed` function.
Options API
data: () => ({
count: 1,
}),
computed: {
doubleCount() {
return count * 2;
},
},
Composition API
import { ref, computed } from "vue";
const count = ref(0);
const doubleCount = computed(() => {
return count.value * 2;
});
In the Composition API, `computed` is defined using the `computed` function.
The specifications for `computed` are the same as in the Options API; you cannot directly modify the value of `computed`.
props
In the Options API, `props` were defined using the `props` property.
In the Composition API, you define `props` using the `defineProps` function.
Options API
props: {
count: {
type: Number,
required: true,
},
},
Composition API
import { ref } from "vue";
const props = defineProps({
count: { type: Number, required: true },
});
Additionally, in a TypeScript environment, strict type definitions are possible.
props: { count: { type?: number, }, },
watch
In the Composition API, you can use the `watch` function to monitor reactive values in the same way as in the Options API.
Options API
watch: {
count(count, oldCount) {
console.log(count);
console.log(oldCount);
},
},
Composition API
import { ref, watch } from "vue";
const count = ref(0);
watch(count, (count, oldCOunt) => {
console.log(count);
console.log(oldCOunt);
});
Using Lifecycle Methods
In the Composition API, you can use lifecycle methods in the same way as in the Options API.
However, be cautious as some method names have been changed compared to the Options API.
The lifecycle methods in the Composition API corresponding to those in the Options API are as follows.
Options API | setup 内のフック |
---|---|
beforeCreate | Not needed* |
beforeMount | onBeforeMount |
beforeUpdate | onBeforeUpdate |
beforeUpdate | onUnmounted |
beforeUpdate | onErrorCaptured |
renderTracked | onRenderTracked |
renderTriggered | onRenderTriggered |
activated | onActivated |
onBeforeMount | onDeactivated |
You can use them by importing each function.
import { onMounted } from "vue";
onMounted(() => {
console.log("onMounted");
});
The above is an example using `onMounted`, but other methods can also be used if you import and define them.
About Provide / Inject
We will also explain about `provide` and `inject`, which are closely related to the Composition API.
Even with the Composition API, you cannot share reactive values between multiple components just by extracting logic and state.
For example, even if you import and use the same `useCounter` composable in two components, `useCounter` is generated in each component, so information cannot be shared between components.
This is where `Provider` comes in.
Below is an example of implementing `Provider`.
useCouter.ts
In Composables, you define a key using `InjectionKey` for referencing.
Next, you provide it in the parent component.
By doing this, you enable even deeply nested child components to share the state of `useCounter`.
App.vue
In child components, you can use `inject` to access what was provided in the parent component.
With this, values updated in the parent component are also conveyed to the child component, enabling sharing between parent and child.
Summary
With Vue.js’s Composition API, it has become easier to “extract and reuse logic.”
In complex applications where components become bloated, you can create components that are easy to read and maintain by separating the logic.
Also, just because the Composition API was developed doesn’t mean that the Options API has become deprecated in Vue 3.
The official documentation clearly states that there are no plans to deprecate the Options API.
Will Options API be deprecated?
While the Composition API offers a high degree of freedom, it is also a feature that is difficult to leverage without considering design and architecture, so thorough consideration is needed when introducing it.
We have introduced the Composition API.
Learn Vue.js with Skilled
Skilled is a practice-focused programming learning service. We are also an official partner of Vue.js, offering services where you can learn Vue.js.
To maximize your learning efficiency and convert it into skills, we are inventing various technologies related to learning, including patented technologies.
We cover learning from markup to application engineering, and by coding while learning practically, you can acquire “skills” rather than just knowledge.
We are currently running a free trial campaign, so if you are interested, please feel free to take advantage of the free trial.
Click here for a free trial of Skilled.