This tutorial is out of date and no longer maintained.
An upcoming Vue update was set to have classes implemented. In React and Angular, we can create components using JavaScript classes. Some people prefer this way of component creation as it can lead to better readability. It can be a confusing tool though since people start to think of JavaScript classes as classes in other languages that have inheritance. JavaScript classes are just syntactical sugar over JavaScript functions however and classes can lead to a bit of confusion.
In Vue, we create components using objects like so:
// standalone
new Vue({ })
// using the CLI
<script>
export default { }
</script>
There was a proposal started on February 26, 2019 on GitHub that would allow us to create components with classes in addition to objects. This was targeted for the Vue 3.0 release.
Here were the initially proposed classes:
class App extends Vue {
// options declared via static properties (stage 3)
// more details below
static template = `<div @click="increment">
{{ count }} {{ plusOne }}
</div>`
// reactive data declared via class fields (stage 3)
// more details below
count = 0
// lifecycle
created() {
console.log(this.count)
}
// getters are converted to computed properties
get plusOne() {
return this.count + 1
}
// a method
increment() {
this.count++
}
}
<template>
<div @click="increment">
{{ count }} {{ plusOne }}
<Foo />
</div>
</template>
<script>
import Vue from 'vue'
import Foo from './Foo.vue'
export default class App extends Vue {
static components = {
Foo
}
count = 0
created() {
console.log(this.count)
}
get plusOne() {
return this.count + 1
}
increment() {
this.count++
}
}
</script>
Pulled directly from the RFC on GitHub:
Vue’s current object-based component API has created some challenges when it comes to type inference. As a result, most users opting into using Vue with TypeScript end up using vue-class-component. This approach works, but with some drawbacks:
vue-class-component
had to implement some inefficient workarounds in order to provide the desired API without altering Vue internals.vue-class-component
has to maintain typing compatibility with Vue core, and the maintenance overhead can be eliminated by exposing the class directly from Vue core.The primary motivation of native class support is to provide a built-in and more efficient replacement for vue-class-component
. The affected target audience are most likely also TypeScript users.
The API is also designed to not rely on anything TypeScript specific: it should work equally well in plain ES, for users who prefer using native ES classes.
Note: We are not pushing this as a replacement for the existing object-based API - the object-based API will continue to work in 3.0.
There are two major reasons why the Class API proposal was dropped:
Composition functions and Classes and Objects would allow us to make the same component 3 different ways. Vue has always focused on developer experience so it’s comforting to see them try to simplify the developer experience again. They feel that 3 ways to do the same thing is not the best.
With the coming composition functions, TypeScript support is one of the main benefits. Support is better in this approach than in the classes approach.
With the two new APIs #22 Advanced Reactivity API and #23 Dynamic Lifecycle Injection, we have a new way of declaring component logic: using function calls.. These are inspired by React Hooks.
In composition functions, a component’s logic will happen in a new setup()
method. It is pretty much data()
but gives us more flexibility using function calls inside of it.
// everything tree-shakable
import {
value,
computed,
watch,
onMounted,
inject
} from 'vue'
const App = {
// same as before
props: {
a: String,
b: Number
},
// same as before
components: {
// ...
},
setup(props) {
// data
const count = value(1)
// computed
const plusOne = computed(() => count.value + 1)
// methods
function inc() {
count.value++
}
// watch
watch(() => props.b + count.value, val => {
console.log('changed: ', val)
})
// lifecycle
onMounted(() => {
console.log('mounted!')
})
// dependency injection
const injected = inject(SomeSymbol)
// other options like el, extends and mixins are no longer necessary
// expose bindings on render context
// any value containers will be unwrapped when exposed
// any non-containers will be exposed as-is, including functions
return {
count,
plusOne,
inc,
injected
}
},
// template: `same as before`,
render({ state, props, slots }) {
// `this` points to the render context and works same as before (exposes everything)
// `state` exposes bindings returned from `setup()` (with value wrappers unwrapped)
}
}
I’m excited to see where the Vue team goes with these “composition functions”. I like the idea of thinking of our components more as composed parts since that’s more in line with a JavaScript way of thinking. Classes lead to people thinking in a more object-oriented way.
This also leans towards a thought process that is similar to how React is moving with React Hooks. The “composition functions” also allow for better TypeScript support which in turn leads to a better developer experience and tooling.
I’m looking forward to seeing where Vue goes next. I don’t mind Vue’s way of declaring components with objects and it’s looking good with the way they are sticking with it.
What are your thoughts on the dropping of the classes proposal?
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!