vue-class-component
vue-class-component copied to clipboard
[Vue v3] Changes for @Component decorator and Vue base class
Summary
-
@Component
will be renamed to@Options
. -
@Options
is optional if you don't declare any options with it. -
Vue
constructor is provided fromvue-class-component
package. -
Component.registerHooks
will move toVue.registerHooks
Example:
<template>
<div>{{ count }}</div>
<button @click="increment">+1</button>
</template>
<script>
import { Vue, Options } from 'vue-class-component'
// Component definition
@Options({
// Define component options
watch: {
count: value => {
console.log(value)
}
}
})
export default class Counter extends Vue {
// The behavior in class is the same as the current
count = 0
increment() {
this.count++
}
}
</script>
// Adding lifecycle hooks
import { Vue } from 'vue-class-component'
Vue.registerHooks([
'beforeRouteEnter',
'beforeRouteLeave',
'beforeRouteUpdate'
])
Details
As Vue v3 no longer provides base Vue
constructor, Vue Class Component will provide it instead. Fortunately, we can add class component specific features in the base class as we define it in Vue Class Component package.
One of the benefits with the new Vue
constructor is we can make @Component
decorator optional. There were non-trivial number of confusions regarding missing @Component
decorator in super class / mixins (e.g. #180). Making decorator optional would solve this problem.
Also renaming @Component
with @Options
would make more sense as it is for adding component options to your class components rather than making a class component.
Since @Options
is optional, having registerHooks
on the decorator will not work. So we will move the method under static field of Vue
constructor.
Alternative approach
Declaring component options as static properties
We could do this to define class component options:
export default class Counter extends Vue {
// All component options are static properties
static watch = {
count: value => {
console.log(value)
}
}
count = 0
increment() {
this.count++
}
}
But it has a drawback: we cannot define static properties / methods not for component options both on userland and library side. e.g. we cannot define static method like registerHooks
on Vue
.
Seems some of the breaking changes may not be fully covered with a codemod.
Is it possible to implement a runtime compatibility layer on top of it in vue-property-decorator
?
Yes, we can provide a runtime compatibility layer. Just wrapping Options
with Component
as Options
provides almost the same API interface and feature with the current Component.
Maybe providing Options
and Vue
from vue-class-component
with minor update would help to migrate.
Is there a way to already test it with the vuejs/composition-api ?? Thanks!
I'm going to create a bridge api for composition functions in a separated issue. -> Edit: created #416
Does the abandonment of the Class API proposal have any affect on this package and whether it would be maintained at the same level in the future? Cheers.
Does the abandonment of the Class API proposal have any affect on this package and whether it would be maintained at the same level in the future? Cheers.
nope, from what I understand this package will always exist and will always have 1st party package status, its just not practical for the base vue package to use classes in todays world.
@ktsn So we did try the latest vue class component beta and while the new props declaration is working just fine, we need to have Watch, Provide and other related Vue features. Putting watch in @Options works but is not expressive enough at all. The static alternative is not yet implemented but would suffer the same issue being static ?
The issue is that we were able to access the class variables through this
inside the method that react to the thing it watch.
This expressivity is needed for a lot of behavior and we are unable to migrate to Vue3 until this crucial limitation is fixed.
@LifeIsStrange like you, our team share with those concerns. Waiting for an update!
Seems that this new API does not match with documentation https://class-component.vuejs.org which is very confusing.
@LifeIsStrange I think having Watch and Provide and other decorators for class methods and fields are part of vue-property-decorators, isn't it?
Already mentioned in the documentation: You may also want to check out the @Prop and @Watch decorators provided by Vue Property Decorator.
@Chris2011 Vue property decorator has not be ported to vue 3 and nobody is working on it for the foreseeable future. This is very worrying for the industry.
@LifeIsStrange well, vue-property-decorator depends on vue-class-component, so I guess they will farely wait for the new version 8 of this package here. :). Just my opinion, no insides.
Hope this situation changes. This two libs belongs to the top of mind of the Vue community!
@Chris2011 that's not how it should work, they should begin working on it while it's in beta. If they need to do some breaking changes to vue class component it will be too late after a stable release
how can we modify a msg in watch method like that
<template>
<div>{{ count }}</div>
<button @click="increment">+1</button>
</template>
<script>
import { Vue, Options } from 'vue-class-component'
// Component definition
@Options({
// Define component options
watch: {
count: value => {
console.log(value)
if(value==10){
this.msg='计数超过10了'
}
}
}
})
export default class Counter extends Vue {
// The behavior in class is the same as the current
count = 0
msg=''
increment() {
this.count++
}
}
</script>
@ktsn
@ZhengXingchi this cannot be used in arrow functions, the following code is work watch: { count( value) { console.log(value) if(value==10){ this.msg='计数超过10了' } } }
Maybe it's time that vue-class-component and vue-property-decorator merge into a single tool? It seems like it would be easier to design a better and more wholistic solution this way.
I totally agree with @theoephraim, I think it would be better and more pragmatic for the class component ecosystem to merge these two libraries. I also think it is the wish of many users of this library.
I am with you. I use class component style to my project. Don't migrate to Vue 3 until this movement is mature!
I am migrating to vue 3 . I am not be able to access the props value in my class instead it gives me 0 and not printing in console the latest value i am using on prop. On template it working fine but i want the lateast value of titleComponent in my class
[
import { Options, Vue } from "vue-class-component";
@Options({
props: {
titleComponent: Number
}
})
export default class StorePin extends Vue {
private titleComponent = 0;
mounted()
{
console.log(this.propValue);
}
get propValue()
{
return this.titleComponent;
}
incremnt()
{
this.titleComponent ++ ;
}
}
</script>
```](url)
@aliibrahimroshan If you didn't find the answer yet: See #465
I've done it like that and not in the @Options
class Props {
// optional prop
foo?: string
// required prop
bar!: string
// optional prop with default
baz = prop<string>({ default: 'default value' })
}
export default class MyComp extends Vue.with(Props) {}
I use class component style to my project. filter
@Options({ // props: { // docList: Array // }, filters: { formatTime: (time: string) => { console.log('time', time) } }, watch: { count: value => { console.log(value) } } })
[Vue warn]: Property "filterName" was accessed during render but is not defined on instance
use vue-class-component in .tsx
.
- render function
I have to set it to any
The new API is not reflected in the document https://class-component.vuejs.org/, and this document is a little rough, I hope to improve the document, if it will be maintained in the future, it will be better to put it in the VUE3 document
For those running into issues with Vue3 and vue-property-decorator; have a look at this package: https://github.com/calebeaires/vue-decorator
That solved most of my issues.
For those running into issues with Vue3 and vue-property-decorator; have a look at this package: https://github.com/calebeaires/vue-decorator
That solved most of my issues.
Thats cool and also to add it here, wouldn't it be better to make a PR to this project here @calebeaires ?
I totally agree with @theoephraim, I think it would be better and more pragmatic for the class component ecosystem to merge these two libraries. I also think it is the wish of many users of this library.
I agree with you @theoephraim ,nicolidin too
how can we modify a msg in watch method like that
@ZhengXingchi
You can use watch
through this.$watch
like bellow:
count = 0;
created() {
this.$watch("count", () => {
console.log(count updated);
this.msg = "new string" // you can access to this
console.log(this.msg)
});
}
@ktsn Hey guys. Thank you for your hard work.
One question from me: will it possible to make the v8
work within vue-2
+ vue/composition-api
plugin environment?
It's pretty critical for us since we're going to smoothly transition from vue-2 to vue-3 that's why we decided to start touching the composition-api a little bit within the current codebase. Also, we've enabled some of the recommended vue3 es-lint rules to help us transition a bit since no vue-3 "migration build" is provided yet (and nobody knows when it happens).
So the main problem is that 7.2.6
doesn't properly work with setup
approach since we heavily rely on Vetur & VS Code in our daily work and template interpolation doesn't recognise anything that comes from setup
declared inside @Component
decorator.