Vue: Callback refs as additional alternative to "named" refs

Created on 28 Jun 2017  ·  8Comments  ·  Source: vuejs/vue

What problem does this feature solve?

Currently if you want to use refs to elements (DOM elements or Vue components - see attribute/prop "ref") you have to provide a string as "ref" attribute. A callback function as "ref" attribute like in React is currently not supported in Vue.
It would be great if also callback functions could be provided as "ref" attributes (especially when doing a bit more advanced stuff using the "render" function).

The callback function should be called both when the referred element is created and also when it is disposed (React for example passes null in the latter case).

It seems that this feature had already been implemented in the past but has been reverted later (I do not know for what reasons the changes have been reverted) => see: "[WIP] Support for ref callback #4807"

Thank you very much.

What does the proposed API look like?

Please see line 178 here:
https://github.com/vuejs/vue/pull/4807/commits/90c6c2902b1f124093ad0d514984230194cb818e

const myRefCallback(ref, remove) {...} (where "remove" is boolean) seems to me like a better solution that the one that is used in React where in the "remove" case the ref callback function is just called with null.

feature request

Most helpful comment

Maybe we can use directive to implement ref callback function.
I published a plugin vue-ref, you can try it.
I used it in ant-design-vue and found no problems for the time being.

All 8 comments

FYI this feature has been dropped at the time because of this bug https://github.com/vuejs/vue/issues/4998

I am not very sure what you preferred, but i think v-bind:ref could help with most of the situations. Although using :ref with v-for will still make the $refs be Arrays and disposing a components will not destroy the Array but destroy the components inside (may result in empty array/s).
Take a look at this example: https://jsfiddle.net/no1xsyzy/036scaat/4/, pay attention to the console output.

Thanks a lot, no1xsyzy, for that information and your demo.
But the problem is a bit deeper:
'String refs' are fine - I normally use them as-is in most cases.
But 'callback refs' are far more powerful.
Especially for those cases where you do not use templates (let's say you develop some kind of extension library for Vue) the lack of 'callback refs' may really be a show stopper.

That's why Facebook/React have switched from 'string refs' to 'callback ref':
https://facebook.github.io/react/docs/refs-and-the-dom.html#legacy-api-string-refs

Moreover in Vue it's not possible to use refs in templates for functional components (as that would require callback refs).
In React that's possible:
https://jsfiddle.net/ozjdyr9L

In some cases and only for non-functional component it may be possible to simulate the behavior of callback refs by using unique generated ref names and some additional logic in certain lifecycle methods - but that would be really ugly, in some cases slow and not that powerful.

The feature to allow 'ref callback' would open Vue some really interessting new possibilites.

I changed my mind regarding the above suggested signature of the callback function:
I think it would be better to make the callback signature somehow compatible with React to make it easy for wrapper or whatsoever libraries that provide something that could be used for both React and Vue.

Instead of
function myRefCallback(ref, remove) {...}

I would now suggest:
function myRefCallback(ref, prevRef) {...}

Means "myRefCallback" will either be called:
myRefCallback(ref, null) (on rendering)
or
myRefCallback(null, ref) (on removing)

React does not have that second argument in the ref callbacks, but the first argument would behave exactly like in React.

I'm also interested in Vue implementing callback refs. They're so much more powerful in my opinion.

In my situation, as a workaround, I've resorted to storing a reference to the vnode whose component instance I want a ref for, then delegating to vnode.componentInstance to get the ref at a later time.

Unfortunately I have no way of knowing when the instance has been created/mounted, because until then vnode.componentInstance is undefined. I'm pulling the instance instead of relying on a push from the framework.

Frankly speaking I don't think that it's a good idea. Function as a ref allows to do crazy side effect stuff. Moreover, you can create internal state using closures and you will recreate this internal state each time your render function is called. Render function of functional components are called together with parent's render function

So, eventually it may have performance issues

Maybe we can use directive to implement ref callback function.
I published a plugin vue-ref, you can try it.
I used it in ant-design-vue and found no problems for the time being.

I really don't know why is this issue is neglected.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

paceband picture paceband  ·  3Comments

wufeng87 picture wufeng87  ·  3Comments

loki0609 picture loki0609  ·  3Comments

seemsindie picture seemsindie  ·  3Comments

lmnsg picture lmnsg  ·  3Comments