Closed filipsobol closed 1 month ago
Your proposition makes sense to me.
Vue 3 still exposes $refs
in views, so why not expose it inside SetupContext
?
It would be more consistent.
I, too, think that the current design for using DOM refs with composition apis is not intuitive. It caused me a fair bit of frustration on my first try.
Related: vuejs/vue-next#660, I suggested that when using composition api template
refs
should be written to any property, even if it's not backed by aref
(could be a reactive object, or even just a plain object if you don't care about reactivity). Didn't get much support.
I don't disagree on some points, but I am also unsure if one or the other is better.
I personally like the ref API as it is, but I'll admit it has felt a little awkward when explaining to others. The link between ref()
and ref=
feels more like a coincidence than a logical relationship.
That said, being able to populate reactive refs with DOM refs allows for more easily decoupling the logic around those refs. With refs on the setup context interface, you would have to pass that to composition functions that deal with refs, and I don't see any good way you could rename them. For example:
setup(_, { refs }) {
const { focus /* method */ } = useFocus(refs)
return { focus }
}
The problem I see with this example is that we have to look into the useFocus
function to know what our ref must be named. And the only way I see to provide the ability to rename the ref is an extra parameter to that function to use as a dynamic key. When using ref
as the API has it now, it's as simple as renaming the variable returned from useFocus
.
Also, on a couple of the points you bring up, I'm not sure the alternative works any better:
refs
object in the alternative API also has to match the ref in the template. You don't get autocomplete, so you need to spell the key correctly, same as spelling the variable correctly. refs
object.Other thoughts:
ref
as templateRef
. That would make it clear.templateRef
helper with a return type of readonly (it just wouldn't actually be readonly) so that folks will know not to touch it.templateRef
helper, you could do other useful things like adding dev mode validation to ensure it actually gets populated, and with the correct kind of thing.That said, being able to populate reactive refs with DOM refs allows for more easily decoupling the logic around those refs. With refs on the setup context interface, you would have to pass that to composition functions that deal with refs, and I don't see any good way you could rename them
Fair point. The same could be said about passing a prop to a function, which is probably a lot more common than passing a ref. I think the only way to do the currently is:
setup(props, { refs }) {
// Example with refs, props works in exactly the same way
const { el1, el2: renamed } = toRefs(refs);
useFocus(renamed);
}
I think passing DOM elements to mixins should be an unusual case. The "better" way to compose stuff that manipulates DOM is to encapsulate the behavior in either a directive or a component.
You example useFocus
screams v-focus
to me (I know, it's just an example. Not saying there are no good use cases, but saying they shouldn't be common).
It seems to me that using the ref inside the component itself is the main use case and I wouldn't mind doing refs.element
.
One thing that annoys me a lot is that there would be no strong typing, unlike props. Unless you declare refs in some way, the best you could do is refs: Record<string, Element>
. Which falls short of validating el2
is the right name and fails to provide a stronger type for it (e.g. HTMLInputElement
).
And that's not even correct since refs can also be arrays (when used in v-for
).
(Can Vetur help?)
Typing is a big drawback :(
The newly introduced useTemplateRef()
solves this issue.
Hi,
I was playing around with Composition API and IMHO access to template refs is confusing, slightly complicated and might cause unexpected errors in the code.
1. Problem
Currently to use template refs I have to:
Problems with this approach: 1.) Without type annotation this line isn't in any way different from regular
refs
used to store reactive data:const input = ref(null);
. 2.) Name of the variable must matchref=""
in the template. I personally like to addElement
(eg.inputElement
) to variable names to indicate that they are DOM elements. 3.) I have to look into bothsetup
method and template to know that this is a reference to DOM element. 4.) Whenref=""
in the template is renamed, the name of the variable must also be updated. 5.) There might a case when someone tries to useref
with the same name asref=""
in the template and assign some value to it - Vue will keep overriding it to the DOM element.2. Possible solution
In Vue 2 with
@vue/composition-api
plugin it's possible to access template refs from context like so (TypeScript will throw an error, becauserefs
doesn't exists onSetupContext
interface, however it works fine):However the same property doesn't exist in Vue 3 (SetupContext interface).
I think that this approach is much better, but I'd like to know your opinion.