vue-class-component icon indicating copy to clipboard operation
vue-class-component copied to clipboard

[Vue v3] Changes for @Component decorator and Vue base class

Open ktsn opened this issue 4 years ago • 61 comments

Summary

  • @Component will be renamed to @Options.
  • @Options is optional if you don't declare any options with it.
  • Vue constructor is provided from vue-class-component package.
  • Component.registerHooks will move to Vue.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.

ktsn avatar Mar 19 '20 11:03 ktsn

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?

haoqunjiang avatar Mar 19 '20 14:03 haoqunjiang

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.

ktsn avatar Mar 19 '20 14:03 ktsn

Is there a way to already test it with the vuejs/composition-api ?? Thanks!

nicolidin avatar Mar 24 '20 16:03 nicolidin

I'm going to create a bridge api for composition functions in a separated issue. -> Edit: created #416

ktsn avatar Mar 25 '20 12:03 ktsn

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.

the-emerald avatar May 30 '20 22:05 the-emerald

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.

HIMISOCOOL avatar Jun 18 '20 23:06 HIMISOCOOL

@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 avatar Oct 09 '20 10:10 LifeIsStrange

@LifeIsStrange like you, our team share with those concerns. Waiting for an update!

calebeaires avatar Oct 18 '20 15:10 calebeaires

Seems that this new API does not match with documentation https://class-component.vuejs.org which is very confusing.

iklemm avatar Nov 01 '20 17:11 iklemm

@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 avatar Nov 08 '20 01:11 Chris2011

@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 avatar Nov 08 '20 01:11 LifeIsStrange

@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.

Chris2011 avatar Nov 08 '20 10:11 Chris2011

Hope this situation changes. This two libs belongs to the top of mind of the Vue community!

calebeaires avatar Nov 08 '20 10:11 calebeaires

@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

LifeIsStrange avatar Nov 08 '20 14:11 LifeIsStrange

how can we modify a msg in watch method like that

image

<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>

ZhengXingchi avatar Dec 01 '20 07:12 ZhengXingchi

@ktsn

ZhengXingchi avatar Dec 01 '20 07:12 ZhengXingchi

@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了' } } }

ygj6 avatar Dec 08 '20 08:12 ygj6

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.

theoephraim avatar Dec 15 '20 18:12 theoephraim

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.

nicolidin avatar Dec 15 '20 18:12 nicolidin

I am with you. I use class component style to my project. Don't migrate to Vue 3 until this movement is mature!

calebeaires avatar Dec 16 '20 14:12 calebeaires

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 avatar Dec 18 '20 23:12 aliibrahimroshan

@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) {}

zischler avatar Dec 29 '20 13:12 zischler

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

2222222

liuying1214 avatar Jan 07 '21 08:01 liuying1214

use vue-class-component in .tsx.

  • render function image

I have to set it to any

bhabgs avatar Jan 15 '21 03:01 bhabgs

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

hsbtr avatar Jan 20 '21 08:01 hsbtr

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.

websmurf avatar Jan 29 '21 15:01 websmurf

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 ?

Chris2011 avatar Jan 29 '21 15:01 Chris2011

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

softboy99 avatar Feb 10 '21 08:02 softboy99

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) 
  });
}

nicolidin avatar Feb 23 '21 19:02 nicolidin

@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.

fobdy avatar Mar 12 '21 08:03 fobdy