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

Template Refs in v-for not working #5525

Closed
davidmarkl opened this issue Mar 5, 2022 · 37 comments · Fixed by #5118
Closed

Template Refs in v-for not working #5525

davidmarkl opened this issue Mar 5, 2022 · 37 comments · Fixed by #5118
Labels
❗ p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. has workaround A workaround has been found to avoid the problem 🐞 bug Something isn't working

Comments

@davidmarkl
Copy link

Version

3.2.31

Reproduction link

stackblitz.com

Steps to reproduce

Open the DevTools and look at the console.logs from onMounted.
You now see three logs, each representing a different template Ref.
Log one and three are a single template ref and an array filled with function refs. They are working fine as expected.
The issue is that the second ref is not returning an array of elements from the v-for but stays empty as initialized.

What is expected?

Template Ref on the v-for should be a DOM NodeList or an Array of DOMElements

What is actually happening?

The initialized ref([]) stays empty

@lidlanca
Copy link
Contributor

lidlanca commented Mar 6, 2022

sfc playground

this works in playground, and "prod" build
but fails in vite/vue dev build

@D4RKAR117
Copy link

D4RKAR117 commented Mar 6, 2022

I have the same problem too, and i can give another repro case here, the template refs in devtools seems to be a different thing than the references given in script setup. I tried to use function refs but the callback typings seems to be broken and the el param gets evaluated in typescript as any. so vue-tsc or other typechecking solutions will fail under it's usage. The only way i managed to access the template refs without much headache but more verbosity is to access $refs directly into the template, and either execute or pass the value or callback in the template

@LinusBorg
Copy link
Member

duplicate of #5447

@lidlanca
Copy link
Contributor

lidlanca commented Mar 8, 2022

not a duplicate of #5447

see repro in my comment above the same code doesn't work in vite dev build.

there is a different code generation between dev and prod.

@LinusBorg LinusBorg reopened this Mar 8, 2022
@ILikeCoder
Copy link

I have the same problem too, and i can give another repro case here, the template refs in devtools seems to be a different thing than the references given in script setup. I tried to use function refs but the callback typings seems to be broken and the el param gets evaluated in typescript as any. so vue-tsc or other typechecking solutions will fail under it's usage. The only way i managed to access the template refs without much headache but more verbosity is to access $refs directly into the template, and either execute or pass the value or callback in the template

Have you solved this problem? How to solve it

@LinusBorg
Copy link
Member

@lidlanca i opened for further evaluation but don't really see the difference to #5447 ? #5447 also only worked in prod/playground, and that's because of the render function inlining.

@ILikeCoder
Copy link

@lidlanca我打开以进行进一步评估,但并没有真正看到与#5447的区别?#5447也只在 prod/playground 中工作,这是因为渲染函数内联。

Expect to get feedback on this problem, in the process of writing business code, stuck in this piece

@lidlanca
Copy link
Contributor

lidlanca commented Mar 8, 2022

@LinusBorg
I didnt realize #5447 was dev / prod build sensetive.

In that case this issue does share a common root cause.

However i am not sure my pr covers the dev build case. The Ref are not normalized to even hit the fix code path

@LinusBorg
Copy link
Member

I'd have to take a closer look, but in dev, the ref would be part of setupState so it seemed to me your change would fix the problem.

@lidlanca
Copy link
Contributor

lidlanca commented Mar 8, 2022

@LinusBorg ignore this

The Ref are not normalized to even hit the fix code path
that was due to a : binding on the ref when I tested.

The PR does indeed fix this issue for dev mode!

A possible workaround for the current limitation is:

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

//escapse template unwrapping
const skipUnwrap = { el: ref([]) };
// for convenience
let el = computed(() => skipUnwrap.el.value);

onMounted(() => {
  console.log(el.value);
});
</script>

<template>
  <div>
    <div v-for="i in 'hello'" :key="i" :ref="skipUnwrap.el">{{ i }}</div>
    Total Refs: {{ el.length }}
  </div>
</template>

https://stackblitz.com/edit/vitejs-vite-jfeskg?file=src/App.vue

@LinusBorg LinusBorg added ❗ p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. 🐞 bug Something isn't working has workaround A workaround has been found to avoid the problem labels Mar 9, 2022
@ZerroRt
Copy link

ZerroRt commented Mar 9, 2022

Same problem :( , hope this bug is fixed soon.

@ILikeCoder
Copy link

@lidlanca Thank you very much for your method, as far as I am concerned, there is no problem now. good good

@calebwaldner
Copy link

calebwaldner commented Mar 25, 2022

Workaround works 👍🏼 Looking forward to bug fix. Tx

@Alexandre-cibot
Copy link

Same issue here, thank you for the workaround waiting for the fix. 👍

@jifka
Copy link

jifka commented Apr 7, 2022

I'll add my name to the list of people affected by this. I am converting a mid-sized app to the composition API and this breaks some core functionality. I'll try the workaround, but it seems shaky.

@chiboreache
Copy link

it's still works only with wrapper...

var itemRefs = ref( [] )
var skipUnwrap = { itemRefs }


div(
   v-for=" i in ls " :ref=" skipUnwrap.itemRefs "
  )

@Sven89
Copy link

Sven89 commented Jul 6, 2022

same problem. Still only works with wrapper

@vervelover
Copy link

not working for me as well

@edison1105
Copy link
Member

edison1105 commented Jul 7, 2022

@Sven89 @vervelover
this because $setup.itemRefs(DEV) and itemRefs.value(PROD) both are Proxy values.

as a workaround.

@vervelover
Copy link

Hi, thank you for the answer, unfortunately all workarounds posted seem to add values to the ref array, but contrary to what I was able to do in vue 2, in vue 3 I cannot access any method defined on the ref. So let's say I have a validate() method on the first ref of the itemRefs array, in vue 2 I was able to call it like this:

itemRefs.value[0].validate()

But how do I call the method in vue 3 Proxy values?

@liulinboyi
Copy link
Member

Hi, thank you for the answer, unfortunately all workarounds posted seem to add values to the ref array, but contrary to what I was able to do in vue 2, in vue 3 I cannot access any method defined on the ref. So let's say I have a validate() method on the first ref of the itemRefs array, in vue 2 I was able to call it like this:

itemRefs.value[0].validate()

But how do I call the method in vue 3 Proxy values?

Use defineExpose()😉, docs.

@vervelover
Copy link

Use defineExpose()wink, docs.

That was awesome, thank you!

I still do not understand why this bug is closed though, because I still get an empty array of refs when not using the object wrap workaround..

@jifka
Copy link

jifka commented Jul 7, 2022

After I updated with the version that fixed it, I was able to remove the workaround and ref worked properly again. Unless there was another regression, I can attest to the bug having been fixed.

@edison1105
Copy link
Member

@vervelover
:ref="itemRefs" value only support string, ref, function.
itemRefs in template will be compiled to $setup.itemRefs(in DEV) or itemRefs.value(in PROD)
it unwrap into a Proxy value. so this is a limitaion for directly use a ref in :ref="".

@johanmolen
Copy link

I experienced this issue yesterday in the newest Vue version. Only in Vite build not in Vite dev.

With the wrapper it worked in both. So this issue is still relevant?

@liulinboyi
Copy link
Member

I experienced this issue yesterday in the newest Vue version. Only in Vite build not in Vite dev.

With the wrapper it worked in both. So this issue is still relevant?

Can you provide a minimum reproduction? Thanks.

@johanmolen
Copy link

@liulinboyi

This is a simplified example:
https://stackblitz.com/edit/vitejs-vite-bqescg?file=src/App.vue

Works fine in dev but not once it is builded.

@liulinboyi
Copy link
Member

@liulinboyi

This is a simplified example: stackblitz.com/edit/vitejs-vite-bqescg?file=src/App.vue

Works fine in dev but not once it is builded.

I have download stackblitz.com/edit/vitejs-vite-bqescg?file=src/App.vue to local and build use Vite, but it will also work fine.

ref-build

@johanmolen
Copy link

@liulinboyi any special configs options used there?

@liulinboyi
Copy link
Member

@liulinboyi any special configs options used there?

The repository is here.

@johanmolen
Copy link

@liulinboyi gonna test this next week, thanks!

@johanmolen
Copy link

@liulinboyi I cant explain why but it is working now (after a node_modules delete and reinstall) haha. Thanks anyway!

@flora-le
Copy link

nothing is working and gives me headache omg. The value of ref, no matter what i do (skip unwrap, binding with function and push), is a proxy and I can't access anything. When i try to access with myArray.value[0], it gives undefined

image

@liulinboyi
Copy link
Member

nothing is working and gives me headache omg. The value of ref, no matter what i do (skip unwrap, binding with function and push), is a proxy and I can't access anything. When i try to access with myArray.value[0], it gives undefined

image

Can you provide a minimum reproduction? Thanks.

@Seanitzel
Copy link

Seanitzel commented Apr 23, 2023

Also spent a bit of time on this, the way it works for me:

<script setup>
const items = ['i1', 'i2', 'i3'];
const elRefs = reactive([]);

function updateRefs(el, index) {
  elRefs[index] = el;
}
</script>

<template>
  <div>
    <div v-for="item, index in items" :key="index"
             :ref="(el) => getPlayerRef(el, index)">
    {{ item }}
    </div>
  </div>
</template>

Also works with components and exposing function on these components.

@madsh93
Copy link

madsh93 commented Apr 26, 2023

Also spent a bit of time on this, the way it works for me:

<script setup>
const elRefs = reactive([]);

function updateRefs(el) {
  elRefs[index] = el;
}
</script>

<template>
  <div>
    <div v-for="i in 5" :key="i" :ref="updateRefs">
    {{ i }}
    </div>
  </div>
</template>

Also works with components and exposing function on these components.

Hey @Seanitzel

Where do you get the index inside your updateRefs from?

@Seanitzel
Copy link

Seanitzel commented Apr 28, 2023

@madsh93 Oops my bad, messed up the rewrite from my code to the comment lol

Edited my comment, should be clear now :)

@github-actions github-actions bot locked and limited conversation to collaborators Sep 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
❗ p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. has workaround A workaround has been found to avoid the problem 🐞 bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.