Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to create functional component in @Component? #120

Closed
lijialing888 opened this issue Jul 5, 2017 · 9 comments
Closed

How to create functional component in @Component? #120

lijialing888 opened this issue Jul 5, 2017 · 9 comments

Comments

@lijialing888
Copy link

lijialing888 commented Jul 5, 2017

Hi guys,

How to create functional component in @component?

import * as Vue from 'vue'
import Component  from 'vue-class-component'

@Component({
    props: ["a"]
    functional: true
})
export default class XXX extends Vue {

}

It prompts error in Visual Studio Code:

[ts] Argument of type '{ functional: boolean; }' is not assignable to parameter of type 'VueClass'.
  Object literal may only specify known properties, and 'functional' does not exist in type 'VueClass'.
@ktsn
Copy link
Member

ktsn commented Jul 6, 2017

We need to declare an additional type for @Component decorator. Thanks for reporting this.

@kaorun343
Copy link
Contributor

I just wondered the benefit of using @Component decorator for functional components because this is undefined in a functional component.

@ktsn
Copy link
Member

ktsn commented Jul 7, 2017

Oh, indeed.

@lijialing888 Why do you want to use @Component for function components?

@ktsn
Copy link
Member

ktsn commented Aug 5, 2017

Closing since there would not be benefit to use class style syntax for a function component as @kaorun343 described.

@marcosmoura
Copy link

@ktsn
Let's suppose that I don't want to render any template or I need an empty render function, but still have the ability to use the decorator while creating functional components. Look at this example:

import { Component, Vue } from 'vue-property-decorator'

@Component({
  functional: true,
  props: {
    theme: {
      type: String,
      default: 'default'
    }
  }
})
export default class Stylesheets extends Vue {
  // A bunch of Vue lifecycle methods here and there...
  render () {
    return null
  }
}

The functional: true will raise an error saying that the functional property is not assignable of type VueClass<Vue>.

In the utils.ts file, there is the following line:

export function createDecorator (factory: (options: ComponentOptions<Vue>, key: string, index: number) => void): VueDecorator {

The type is ComponentOptions (that do not have functional). By changing the line including the functional component type, the decorator works just fine and will inject the functional: true.

export function createDecorator (factory: (options: ComponentOptions<Vue> | FunctionalComponentOptions<Vue>, key: string, index: number) => void): VueDecorator {

Does it make sense to change it to something like that? There is some side effects that this could raise?

Or maybe a safer @FunctionalComponent with the same goods as @Component...

If so, a PR on this matter is welcome?

@DrSensor
Copy link

DrSensor commented Mar 16, 2018

@marcosmoura I think adding the additional decorator @FunctionalComponent is safer. Union type cannot deeply predict which type to use when assigned, for example in using this.$refs

// will error because typescript will assume the type of $refs is Element[]
this.$refs.upload.active = true

// this will work
const upload = this.$refs.upload as MyComponent
upload.active = true

So if it use ComponentOptions<Vue> | FunctionalComponentOptions<Vue> then the options object parameter must be typecasted

@Component({
  functional: true
} as FunctionalComponentOptions)
export default class Stylesheets extends Vue {}

@ktsn In my opinion, adding support for functional based class can enhance the usage of template tag for functional component (especially in validating props value)

<template functional>
  <rect :width="props.size" :height="props.size">
    <slot></slot>
  </rect>
</template>
import { Prop, FunctionalComponent, Vue } from 'vue-property-decorator'

ensureSize(val: number) {
   return val > 10 && Math.sqrt(val) < 300
}

@FunctionalComponent()
export default class Square extends Vue {
  @Prop({ default: 50, validator: ensureSize })
  size: number
}

@netstuff
Copy link

netstuff commented Jul 24, 2018

Does anybody solve this problem? I trying to make recursive scoped slots for tree-component and I think that I have to access native render method for injecting $scopedSlots property next to children components. What do you think about it, guys?

@antoniogiroz
Copy link

Any solution for this?

@ktsn
Copy link
Member

ktsn commented Aug 4, 2018

Just use Vue.extend...

import Vue from 'vue'

export default Vue.extend({
  functional: true,
  render(h, ctx) {
    // ...
  }
})

As it's already pointed out the former of this issue, using class style syntax for functional component does not have benefit since functional component does not have its instance. It won't included in this lib since class style functional component does not follows standard class semantics (not have instance, this is undefined ...).

@vuejs vuejs locked and limited conversation to collaborators Aug 4, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants