-
Notifications
You must be signed in to change notification settings - Fork 545
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
Composition API (revised from #42 Function-based Component API) #78
Conversation
Looks like a great iteration over the previous API. The explanation as to how it all works and comes together was also really good. I did feel a tiny bit lost in the middle though, seeing so many hypothetical examples outside the normal intended usage, but that may have been simply due to the pace I was reading at or due to my mind wondering and wondering if I could... repurpose this API to somehow run lit-html with Vue's reactivity system... Actually, that makes me wonder, for the examples where we see the API used outside of a component context, would anything work properly? Could I use If this documentation is to be repurposed as a guide in the future (e.g. after release), perhaps a nice and short coloured "warning panel" above those code samples would be good to warn the user that the code is just for demonstration purposes. I did notice there were already warnings but I couldn't guess their scope/severity. |
@ceigey The reactivity API should work outside of Vue components. |
This makes me so incredibly happy! 🙌 The general direction of the updated proposal is excellent and much more clear. It's very well done. The addition of |
Great stuff. May I ask again why Also, is there anyway to set |
Would there be an official naming guidelines for refs? E.g. prepending with |
This looks really good! I wonder, besides from taking inspiration from React hooks, is there a reason the functions follow the use* naming convention? IIRC the naming convention is to remind the user that the rules of hooks apply, but it seems like Vue doesn’t have any such rules. |
@ycmjason const readonlyWindowWidth = computed(() => window.innerWidth); |
Super well written! And, as someone who followed all the crazy ups and downs of the original RFC, I think this revision did an excellent job of addressing most of the overarching themes of that discussion 👌 |
maybe there should have a lifecycle hook called |
Is there a plan to retire the V2 api in the future, perhaps in V4 or later, in favor of this new proposal? |
vue-functional-api plugin will be updated or renamed in order to try these new features? 💪🏻 |
i love this api, but i need more example with props, template refs, $listeners, $attrs, and etc. without |
"[...] It has been made available as a 2.x plugin via the vue-function-api library. Note that the library is still reflecting a previous version of this RFC - we are working on updating it to match the latest API specs." (source) |
@pbastowski there's no auch Plan or desire. |
Here's some (hopefully actionable) feedback for the docs:
Apart from that, I feel that whe way the new composition API proposal is presented is great. Kudos to the team. |
|
@Akryum I sometimes also feels it awkward to name a composition function as something like “useCreateFolder”. “use” and “create” are both verbs, making it not valid English. |
To me it reads like "use create folder feature". |
I like the new API name, since the previous name made people to mistook the API to be FP. Once they actually start using the API it should become clear to them that there's no paradigm shift to be made. What is unclear to me now, though, is about
If possible, I would prefer not having to unwrap |
I am confused by the way you introduce the Ref-like container with computed and
but then you introduce automatic ref unwrapping when used in reactive objects, which gets rid of this trade-off:
So it looks like these Ref-like containers, while being unavoidable, could just be an implementation detail that users would not have to deal with directly if they are just using
I would like to understand why you think reactive objects could not be the standard pattern returned by composition functions. What is the usecase for a composition function that is required to only return a primitive, and not a reactive object instead ? It is also still not clear which one between |
I'm also facing the same confusion on when to use |
Yes. inject always returns a ref
Yes. inject always returns a ref. |
Not entirely, as the section that you quote right after demonstrates. Template refs are another example. I would like to understand why you think reactive objects could not be the standard pattern returned by composition functions. What is the usecase for a composition function that is required to only return a primitive, and not a reactive object instead ? Like the quote says being said, you of course can use useDragOver(elementRef) {
const state = reactive({ isDraggingOver: false })
watch(() => elementRef,
(el) => {
// pseudocode, don't do this, won't work reliably because DnD API sucks.
el.addEventListener('dragenter', () => state.isDraggingOver = true)
el.addEventListener('dragleave', () => state.isDraggingOver = false)
}
)
return state But then people might want do this: const { isDraggingOver } = useDragOver(elementRef) ...and it won't work, the connetion to the function's internal So People have to remember do: const { isDraggingOver } = toRefs(useDragOver(elementRef)) Or, you simply use a ref in the first place: useDragOver(elementRef) {
const isDraggingOver = ref(null)
watch(() => elementRef,
(el) => {
// pseudocode, don't do this, won't work reliably because DnD API sucks.
el.addEventListener('dragenter', () =>isDraggingOver.value = true)
el.addEventListener('dragleave', () => isDraggingOver.value = false)
}
)
return isDraggingOver Then consumers can simply do this:
or, as an Alternative: useDragOver(elementRef) {
const state = reactive({
isDraggingOver: ref(false)
})
watch(() => elementRef,
(el) => {
// pseudocode, don't do this, won't work reliably because DnD API sucks.
el.addEventListener('dragenter', () => state.isDraggingOver = true)
el.addEventListener('dragleave', () => state.isDraggingOver = false)
}
)
return state Now destructuring works as expected - but
Well, you kind of need both to make full use of the API, so there's no single recommended method. that being said, we think that it makes more sense to introduce these new concepts with |
I just want to say, I think this is a great "next version" of the original API RFC. The name is much better too. This new RFC shows very much the willingness of the Vue team to listen and compromise with the community, which is a golden advantage Vue has. Please keep that up! I must admit, I too am now somewhat confused with how Scott |
|
Well, I''d say generally create a new issue with the suggestion, so it gets the proper attention. Scott |
Should this issue be labeled |
hey @mesqueeb I am not sure if your talking about the issue I brought up or not. @smolinari thanks for chiming in. Before I created an issue I was just trying to understand if this even was an issue. Is there already a way to do this? Does it fit within the overall concept of this API? Does it even make sense? :) |
I meant this entire thread should get the label |
Dear Evan, As a matter of syntax, I would like to suggest that instead of using an object with a setup function, we simply export a function instead. I think it would look cleaner. I.e. instead of
We can simply have:
This would save a bit of typing and look a bit nicer. Or perhaps, this could be an alternate syntax and the setup function be preserved for those who wish to mix object syntax and composition syntax. |
How this syntax can support props and components |
Props: same as React functional components, pass as argument. |
@siauderman - I believe there is a necessity of having the Scott |
@siauderman In the beginning there was mention of a short-hand method that I think was the same format you were suggesting, but I am having trouble finding any documentation on it. Maybe it got removed or maybe it still exists, but hasn't been implemented yet in the beta or maybe I am just remembering wrong. I believe it was something like:
Can anyone remember if this was going to be implemented, but was removed for some reason. Maybe because it wouldn't allow the Options Api to continue to work. Or maybe I am missing something. |
It could easily be detected, typeof ...==='function', if it is an object then you can use options API as well, but if not you can't. It's also possible to call it once only if it's a function that's exported. It can be an alternative syntax so those who need to combine composition with options API can continue to use setup(). Anyway, not crucial, a minor suggestion, just syntactic sugar that saves (a very small bit of) typing and a level of indentation. |
@ggedde I also remember the API you are talking about. I recall it was saying (somewhere in RFCs) something like "you can also directly return the setup function as the component definition...". But I failed to find those words too. The closest one I found: |
@ggedde Perhaps you're thinking about the revamped functional components, that indeed have the signature (Composition API, however, allows Directly exporting functions would clash with functional components, and I don't know if Vue could distinguish both at runtime without calling the function at least once. It'd be easy, however, to create a helper at userland: function setup (setupFn) {
return defineComponent({ setup: setupFn })
} That could be used inside a SFC like this: export default setup((props) => {
const foo = ref(props.foo)
return { foo }
}) |
@leopiccionia Technically it's possible to distinguish those two cases: const FunctionalFoo = (props, context) => { ... }
FunctionalFoo.functional = true // Mark it a functional component
export default FunctionalFoo It's not much clear and convenient though. I really do remember I ever saw an RFC saying that you can directly export setup function if you don't need to define other component options (components, props, etc.). However, I tried this approach few minutes ago with latest vue-next and failed. Maybe it was revoked. |
@SilentDepth Yeah, I remember seeing that too and even remember watching a few videos with that in it. My guess it that it got removed. |
I have just noticed that we now have |
There's already |
Actually, are the current functional components even necessary in Vue 3? My understanding is that in Vue 3, they will not offer much of a performance improvement if at all. There is little to distinguish functional components from composition API components (I mean, to my understanding a functional component is just one without reactive state, but reactive states are now merely local variables anyway). |
In edge cases, they are. I think this example is found in the docs: a heading whose level can be bound by a prop, something like: export const Header = (props) => h("h" + props.level, props.title)
Header.props = { level: Number, title: String } You can't manipulate tag names in a template. |
You can do
you can also create a render function in non-functional component, maybe some more options, anyway your example doesn't seem to be the case where functional component was NECESSARY |
@jacekkarczmarczyk |
@jacekkarczmarczyk and as for why functional components are needed at all: You can do anything in a functional component. Like looking at your slots contents and manipulating them. Look no further than Vue core itself for usage: Good luck porting that code to a template. |
component with render function !== functional component So one case is when you want to have simpler code (your previous h1-6 example) Another possible advantage would be performance (cpu/memory), and would be nice to see an example where functional ones are significanlty better than normal. Sure you'll save few bytes and cpu cycles when you have component defined as |
What happens to I've been trying to write loaders for custom blocks in the Composition API. Vue Loader's page on custom blocks presents a fairly simple loader pattern for injecting options into a component:
If you inject a However, when I return to my component and its It makes sense that hey, this is the Composition API you're using, not the Options API. I understand that. But I'd still like to know how I can get the content that I read from custom blocks into the component. I feel like it defeats a bit of the purpose of Vue to not be able to add content to a component through custom blocks or other means. |
Rendered | Source
This is a revised version of #42.
Editorial Updates
Technical Updates
watch
can now work with a single functionvalue
renamed toref
and now works for in-template refsstate
renamed toreactive
computed
now usescomputed({ get, set })
to define writable computed values.Even if you are familiar with the previous proposal, it is strongly recommended to read this new version in its entirety.