Skip to content
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

how can I pass ref to child component #317

Closed
wulucxy opened this issue Apr 24, 2020 · 10 comments
Closed

how can I pass ref to child component #317

wulucxy opened this issue Apr 24, 2020 · 10 comments

Comments

@wulucxy
Copy link

wulucxy commented Apr 24, 2020

I notice in the docs:

https://vue-composition-api-rfc.netlify.app/api.html#ref

When a ref is returned as a property on the render context (the object returned from setup()) and accessed in the template, it automatically unwraps to the inner value. There is no need to append .value in the template:

but sometimes I need to get deep parent's ref like this:

<div id="stage" ref="imgWrapperRef">
  zoom {{ zoom }}
  <div>select: {{ state.annotations.value }}</div>
  <ZoomContainer :controlled="true" :filter="filter" v-bind="zoom">
    <div class="ref">
      <div class="imgWrapper">
        <img :src="currentImg">
      </div>
      <TooltipContainer>
        <!-- vue can not pass ref, sucks~ -->
        <Canvas :imgWrapperRef="imgWrapperRef" v-bind="$props" />
      </TooltipContainer>
    </div>
  </ZoomContainer>
</div>

what I wish is I can pass the original imgWrapperRef to the Canvas component。
Since ref is automate unwrap, I can only the the HtmlElement, instead of the original Ref Object。

do you have any hack solution for this?

@LinusBorg
Copy link
Member

First off, it's not recommended to mutate props, so if you follow general and don't mutate props (emitting events instead), you should be fine with only the value instead of the ref.

If you think that you have an edge case where you need to mutate a prop and therefore need the ref, wrap it in a function that returns the ref, then you can call it in the child to get the ref.

setup() {
  // ...
  const imgWrapperRefFn = () => imageWrapperRef
  // ...
}
<Canvas :imgWrapperRef="imgWrapperRefFn" v-bind="$props" />

@Flamenco
Copy link
Contributor

As a side-note, you cannot embed the function as shown here, because Vue will still unwrap the ref.

<Canvas :imgWrapperRef="() => imageWrapperRef" v-bind="$props" />

@Flamenco
Copy link
Contributor

@LinusBorg As much as I like to follow the 'do not mutate props' mindset, I have found myself more and more passing around reactive properties.

Would a directive like this be possible, to instruct Vue to not unwrap?

<Canvas :imgWrapperRef.ref="imageWrapperRef" v-bind="$props" />

@LinusBorg
Copy link
Member

As a side-note, you cannot embed the function as shown here, because Vue will still unwrap the ref.

<Canvas :imgWrapperRef="() => imageWrapperRef" v-bind="$props" />

Not sure what you mean. Works fine here

@LinusBorg As much as I like to follow the 'do not mutate props' mindset, I have found myself more and more passing around reactive properties.

Would a directive like this be possible, to instruct Vue to not unwrap?

<Canvas :imgWrapperRef.ref="imageWrapperRef" v-bind="$props" />

I don't think that will get support.

@Flamenco
Copy link
Contributor

Flamenco commented Mar 16, 2022

Yes, @LinusBorg , it works, but the syntax is verbose, cumbersome, difficult to manage, and requires the reviewer to inspect the function to see if it does more than just pass in a ref to the component. The suggested directive property would make it very clear as the intent when searching source code and debugging.

It would be nice to have the same succinct syntax in Vue as demonstrated by other directive properties such as stop and prevent.

As I have fully embraced Vue Composition API, almost all of my functions now take MaybeRef arguments, and more often than not I unwrap parameters, even if not refs, future proofing my code if I switch over to refs.

Anyway I just wanted to open that option for discussion, as it relates 100% to this closed issue, and won't pursue it further if convinced that the suggestion has no merit.

@LinusBorg
Copy link
Member

If you want to start the discussion, there's the RFCs repo for that.

@Flamenco
Copy link
Contributor

Flamenco commented Mar 16, 2022

@LinusBorg Take another look at the side-note method I posted. I was pointing out that you cannot embed a callback function returning the ref in the template. You need to define the function in your script... Even if you call the function from the child component, Vue has already unwrapped your return value. Not expected, but fact.

<Canvas :imgWrapperRefFn="() => imageWrapperRef" v-bind="$props" />

In child

const notARef = props.imgWrapperRefFn()

I was hoping this would be a simple syntax, as the ref was not accessed until called, but I found out the hard way it does not work.

@newproplus
Copy link

vue 3.2.45

My code have a parent component pass a ref to slot in a child component,I had tried the ways you said,but it doesn't work for me,I cannot receive the ref in slot,and if I use

const ppp = toRefs(props)

then log ppp and ppp.value, it will be:
eee

ppphas the right attrs,but ppp.value is empty

Does vue not allow child component access parent ref?

@Bond-Addict
Copy link

I too am running into this issue. I need to pass a ref for a form element down to the child which is where the validate method is used to validate the form. The issue is that the ref is present but the value is undefined.

@Fernando12mais
Copy link

Fernando12mais commented Jan 11, 2024

What I did was putting the ref inside the father component, then on the onMounted hook, i get the first children on the father component and assign it to a ref

onMounted(() => {
if (!fatherRef.value) return;
childrenRef.value = fatherRef.value.children[0] as HTMLElement;
manageAnimation("expand");
});

<template>
<div ref="fatherRef">
<slot></slot>
</div>
</template>

if this is a wrapper component i could

<WrapperComponent>

<button>the children ref inside wrapper component has the ref for this button now</button>
 </WrapperComponent>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants