vuejs / vue-class-component

ES / TypeScript decorator for class-style Vue components.
MIT License
5.81k stars 429 forks source link

v8 mixins - created() not called - what am I doing wrong? #514

Closed Giwayume closed 3 years ago

Giwayume commented 3 years ago

I'm using 8.0.0-rc.1.

I have this simple .vue file component. When AppTest is rendered in the DOM, I'm not seeing "hello from mixin!" in the console. Is there something off with this syntax below?

<template>
    <div>
        Hello World
    </div>
</template>

<script lang="ts">
import { Vue, mixins } from 'vue-class-component';

class MyMixin extends Vue {
    created() {
        this.hello();
    }
    hello() {
        console.log('hello from mixin!');
    }
}

export default class AppTest extends mixins(MyMixin) {}
</script>
Kapcash commented 3 years ago

You have to use the @Component decorator on your mixin, or it won't be considered as a Vue component Mixin. This is a common mistake I used to do when I started using this library :)

Also, you don't need to use the mixins() helper when you have only one extend:
export default class AppTest extends MyMixin {}

Giwayume commented 3 years ago

@Kapcash I'm talking about vue-class-component 8.0.0-rc.1 for Vue 3, not the old one for Vue 2.

The @Component decorator no longer exists in this version, it is replaced by @Options, which is optional.

ygj6 commented 3 years ago

I am not quite sure if this's a bug or it's deigned so. The created hook function was called at https://github.com/vuejs/vue-next/blob/master/packages/runtime-core/src/componentOptions.ts#L748

callSyncHook(
      'created',
      LifecycleHooks.CREATED,
      options,
      instance,
      globalMixins
    )
function callSyncHook(
  name: 'beforeCreate' | 'created',
  type: LifecycleHooks,
  options: ComponentOptions,
  instance: ComponentInternalInstance,
  globalMixins: ComponentOptions[]
) {
  callHookFromMixins(name, type, globalMixins, instance)
  const { extends: base, mixins } = options
  if (base) {
    callHookFromExtends(name, type, base, instance)
  }
  if (mixins) {
    callHookFromMixins(name, type, mixins, instance)
  }
  const selfHook = options[name]
  if (selfHook) {
    callWithAsyncErrorHandling(selfHook.bind(instance.proxy!), instance, type)
  }
}

According to the code logic, the created() function with extends and mixins can not be found. Anyway, created() can be called without mixins successfully!

<template>
    <div>
        Hello World
    </div>
</template>

<script lang="ts">
import { Vue, mixins } from 'vue-class-component';

class MyMixin extends Vue {
    created() {
        this.hello();
    }
    hello() {
        console.log('hello from mixin!');
    }
}

export default class AppTest extends MyMixin {}
</script>
Giwayume commented 3 years ago

I usually have several mixins into a single component so the above workaround wouldn't work for me as you can only inherit one class.

Giwayume commented 3 years ago

Tracking here https://github.com/vuejs/vue-next/issues/3038