setup() in extended component is not run
Version
3.0.5
Reproduction link
https://jsfiddle.net/mL4s8k2b/3/
Steps to reproduce
Extending a component having a setup() method does not provide the return value of that very setup() method to the extending component.
This is reflected in the console log: it shows the messages “Hello from normal setup” and “Extends created” but it does not show the message “Extends setup”, i.e. the setup() method in the extended component is never run.
What is expected?
The display of the message “Extends setup”.
What is actually happening?
The message is not displayed.
I mostly copied this issue from #3017 but IMHO it was closed prematurely linking to a comment in issue #1866:
This is intentional.
mixins
is a part of the Options API andsetup
is part of the Composition API. If you are using the Composition API, all logic composition should be done using Composition API.
As this is incorrect (both, mixins and extends appear in the docs under composition) and the comment does not even reason about extends I kindly ask for further clarification.
Your confusion likely stems from ambiguous terms:
- "Composition" as a general term refers to ways in which component logic can be extracted, re-used, and composed in multiple components.
- "The Composition API" refers to all the features provided by and used in
setup()
.
Composition can be achieved by using mixins
/extends
or by using functional composition in setup
- the former was the only way of composition in Vue 2, the latter is a new, alternative way provided in Vue 3.
One of the major reasons for the creation and design of the composition API were issues and shortcomings of the mixin
pattern (read more here), so it's a conscious design decision to not have setup
bleed back into the mixins
pattern.
When using setup
, code reuse should be achieved by extracting logic into functions that can be composed inside a component's setup function - not mixins.
thanks for the reply, @LinusBorg.
code reuse should be achieved by extracting logic into functions that can be composed inside a component's setup function
would you have an example showing what you mean by this? like: here is an extend pattern, and here is the composition api implementing this pattern…?
at the moment i am doing it like this, achieving the “bleeding back” into the extends pattern:
import Page from "./page.vue";
export default {
extends: Page,
setup() {
return { ...Page.setup() };
}
};
Good example - good as in: where it gets a bit philosophical.
- Mixins and composition functions both are used to share code like methods, data, lifecycle hooks etc, usually - not a whole component.
extend
, technically, is also just a mixin but can be used like you do - write a base component and then extend from it, much like you would extend from a class in OO.
Now, composition functions are strictly about sharing behavior - you can not share component config, template/render function etc with it. So I cannot give you an equivalent of what you do with a composition function alone.
While possible to achieve this extending behavior with extends
(when not using setup
, or using the workaround you did), I never found a good use for it, so I would like to understand where you find that to be useful.
In terms of patterns, it's usually more flexible, architecture-wise, to not extend from other components, but compose them - i.e. wrap a base component in another one that can add behavior, or add one in a slot as a child to do that. Extending components in this OO fashion is, in my peception, kind of a relic that doesn't fit well into the way modern frontend code is composed. We don't even cover it in the official guide afaict, just document it in the API section for completeness' sake.
So my reply would be: If you like to do this, use your work around. it's fine, technically. We don't feel that this is a pattern that should be put to the fore-front.
I'm however open to discuss a more specific example and how I would approach it.
thanks for the insights, i always like some philosophical arguments, too.
i am now trying to apply your suggestions and this is what i came up with:
import { components, props, setup } from "./page.js";
import MyComponent from "./my-component.vue";
export default {
components: { ...components, MyComponent },
props,
setup
};
is this the right approach to composing components?
furthermore, i would be interested how to manage a growing amount of such composition functions. if i am not mistaken, those act like interfaces (not in the literal object oriented way) – they need a specific input and provide a specific output.
how would one not get lost in code, especially if there are plenty of those functions? (pointers are appreciated, too.)
That seems like a way to achieve that, but It's always hard to give more specific advice on an abstract example like this one. For example, I'm not sure why you would import the page's child components, and not have a render function on this new created function. I lack context to understand you actually want to achieve.
furthermore, i would be interested how to manage a growing amount of such composition functions.
Just so we're clear: What you do in your example is not a composition function. you are composing component options. A "composition function" would be something like this:
https://youtu.be/Soi7Z6gOQE0?t=2466
If you want to discuss further, visit chat.vuejs.org to talk with the community (you can find me there as well). The Issue tracker is not the right place for discussions about patterns etc.
Also I will close this issue as there's no bug.