vuejs / rfcs

RFCs for substantial changes / feature additions to Vue core
4.85k stars 551 forks source link

Setup sugar cannot pass the ref to the ref function param.But I can get the ref object correctly with no sugar #297

Closed recovery-alt closed 3 years ago

recovery-alt commented 3 years ago

When I use ref function in the parent component and ref string in the children, setup sugar cannot get the refs correctly.Here is my code, or you can view my repo.

App.vue

<template>
  <HelloWorld :ref="setRef" />
</template>
<script lang="ts">
export default {
  setup() {
    const setRef = el => {
      // el is an empty object
      console.log(el); 
    };
    return { setRef };
  }
};
</script>

HelloWorld.vue

<template>
  <div ref="dom">demo</div>
</template>

<script lang="ts" setup>
const dom = ref();
</script>
lmiller1990 commented 3 years ago

I think you just need to do

import { onMounted } from 'vue'

onMounted(() => {
  console.log(dom)
})

In the second one, and you will have your ref? Isn't this just a race condition, where the ref is not initialized until the component is rendered? The first example you call the function, which is only called when the DOM element exists. In the second one, this is not the case. I don't think the two snippets are equivalent.

In general I think you always want to do template ref things inside of onMounted, to ensure the elements they refer to exist.

See this example: https://v3.vuejs.org/guide/composition-api-template-refs.html#template-refs

Also, I should have been more clear, I think this issue should be in vue-next, where the actual code for <script setup> lives. This RFC repo is just for ideas/discussions, not actual bugs.

recovery-alt commented 3 years ago

Thanks for your apply. I will go to the vue-next.

lmiller1990 commented 3 years ago

Did my suggestion work?

recovery-alt commented 3 years ago

I've tried. It doesn't work.

lmiller1990 commented 3 years ago

I just tried and it works fine for me. I did not try your repo yet. I suspect there is no bug, though, I'd have to look more closely and try your code. Maybe this working snippet helps:

<template>
  <img ref="theRef" alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld msg="Hello Vue 3 + Vite" />
</template>

<script setup>
import { onMounted, ref } from 'vue'

const theRef = ref(null)

onMounted(() => {
  console.log(theRef.value)
})

import HelloWorld from './components/HelloWorld.vue'
</script>

image

recovery-alt commented 3 years ago

I think you mistake my problem. I'd like to get the children ref in the parent component using ref function. Then the dom object will pass to the first param of this function setRef. While I use sugar in the children component and set the root element ref="dom", I cannot get the fisrt param correctly in the context setRef.

const setRef = el => {
  // el is an empty object
  console.log(el); 
};
posva commented 3 years ago

Don't duplicate issues, thanks.

Abunuo commented 3 years ago

Don't duplicate issues, thanks.

So, what's the solution? I had a similar problem, but I couldn't find the original problem.

Abunuo commented 3 years ago

I think you mistake my problem. I'd like to get the children ref in the parent component using ref function. Then the dom object will pass to the first param of this function setRef. While I use sugar in the children component and set the root element ref="dom", I cannot get the fisrt param correctly in the context setRef.

const setRef = el => {
  // el is an empty object
  console.log(el); 
};

How did you finally solve it?

lanbin commented 3 years ago

In my case, ref can get value on html tag but get empty object on custom component tag which also use <script setup>.

// NotOk.vue
<template>
   i'm not ok
</template>

<script setup>
</scritp>
// App.vue
<template>
   <div ref="ok">I'm OK </div>
   <not-ok ref="notok"></not-ok>
</template>

<script setup>
    import NotOk from '../components/NotOk.vue'

    import { ref , onMounted } from 'vue'

    const ok = ref(null)
    const notok = ref(null)

    onMounted(() => {
        console.log(ok)  //  {..., value: Proxy(), ...}
        console.log(notok)  // empty object
    })
</scritp>
YannicEl commented 3 years ago

same problem as @lanbin

recovery-alt commented 3 years ago

@Abunuo Give up the sugar, then you can sovle it.

Abunuo commented 3 years ago

@Abunuo Give up the sugar, then you can sovle it.

Thank you. That's what I did.

catch6 commented 3 years ago

same problem as @lanbin

catch6 commented 3 years ago

this really is a bug ,it should not be closed

TheParad0X commented 1 year ago

Why is this closed? Where is the original issue if this is a duplicate? I am having the same Problem 🤔

LinusBorg commented 1 year ago

script setup components are closed by default, they do not expose their state to the parent on the ref instance. The components have to explicitly expose state to the outside world.

See: https://vuejs.org/api/sfc-script-setup.html#defineexpose

However, public APIs like $el are still accessible no matter what.

See this playground