Vue: Mixin inerhitance is inconsistent when used with extends

Created on 10 Oct 2017  Â·  13Comments  Â·  Source: vuejs/vue

Version

2.4.4

Reproduction link

https://jsfiddle.net/eczcLptu/2/

Steps to reproduce

Extend a component and add a mixin

What is expected?

The rule of inerhitance should be

  • component
  • extended component
  • mixin

What is actually happening?

The actual inerhitance is

  • component
  • mixin

This is not clearly documented and therefore a bit missleading. I am not sure wether it can technically count as a bug, but at least it is inconsistent behavoir

Most helpful comment

Unlike lifecycle hooks, methods are not merged, they are overwritten.

All 13 comments

It's working as you expect, the mixin takes precedences, try adding something to child and child_mixin components: https://jsfiddle.net/16Lusyur/
If you put the mixin in Child, then child_mixin would overwrite it as well

No it is not. child_mixin should inerhit getMessage from Child, and then the Mixin should be merged with child_mixin, thus resulting in child_mixin's inerhited getMessage method to override the Mixin, and be the final getMessage

According to the docs, the behavoir you describe should not happen either.

Unlike lifecycle hooks, methods are not merged, they are overwritten.

Options that expect object values, for example methods, components and directives, will be merged into the same object. The component’s options will take priority when there are conflicting keys in these objects:

Then the docs are inaccurate.

they're not:

const a = { foo: () => 'foo' }
const b = { foo: () => 'bar' }
const c = {...a, ...b}
c.foo() // bar

a and b being two methods objects

~edit: ooh, you mean mixin vs component?~

The key problem here is that apparently Vue.extend does not consistently behave with what is noted in the docs. I am very well aware that for two components this is true, but for using the combination of extends and mixin this is not what should happen in a logical OOP paradigm.

Can you explain yourself? What is inconsistent?
to be fair mixins doesn't exist in OOP, so I don't see what you're referring to

The scenario should be like this

Component (Class) A

  • method

Mixin

  • method

Component (Class) B, inerhits component A, mixin of B

  • method _inerhited_ from component A
  • mixin should be merged. _method_ already found because inerhited. _componentB#method_ used

Whereas it is currently like this

Component (Class) B, inerhits component A, mixin of B

  • mixin should be merged. _mixin#method_ used
  • inerhition is ignored

My take on this: https://jsfiddle.net/16Lusyur/1/ - but well, sure as mixins are not reallyâ„¢ some standard, the documentation could just say "Mixins will override anything which the component inherits via extends". I thing this is right now just undocumented.

Well. According to Wikipedia I would not say that there is no "common sense" for mixins. Also I wouldn't say that Vue.extends works consistently here. On the other hand, just documenting this more accurately would have saved some nerves.

IMO, the mixin being local, it should take precedence to the extended component (which is what happens), but local properties take precedence over mixins

This has nothing to do with that mixins are or what is OOP.

Different options in Vue have different merge strategies.

  • Lifecycle hooks are "merged" in a way that preserves all hooks in the inheritance chain, because they do not return values and instead produce side effects.

  • Methods of the same name simply overwrite parent value because methods can return values and it would cause ambiguity on what value to return if they are "merged" into a single function. Same for asset-registration options like directives and components.

I can see what the OP means now, essentially the problem is that the options that comes from extends should take higher priority than options coming from a mixin.

Ok, so I still think the current behavior is expected. This is because in your example the mixin is applied to ChildWithMixin instead of Child. The mixin is considered as part of ChildWithMixin's own options and would overwrite whatever is inherited from Child.

If the mixin is applied directly to Child, then you'd see child logged instead.

However, in general, I don't like the idea of over-applying OOP when composing UI components, especially with confusing overrides like this.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lmnsg picture lmnsg  Â·  3Comments

fergaldoyle picture fergaldoyle  Â·  3Comments

gkiely picture gkiely  Â·  3Comments

seemsindie picture seemsindie  Â·  3Comments

loki0609 picture loki0609  Â·  3Comments