-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
Querying this.array.length in ref method causes recursive loop #3653
Comments
This hasn't anything to do with arrays in particular. The issue is that the template ref function is run inside the render phase, during which you should not have any side-effects that , as that would trigger a re-render. The same problem would, for example, manifest if you do this: <template>
<h1> {{ msg = msg + '!' }}</h1>
</template>
<script>
export default {
data: () => ({
msg: 'Hello World'
})
}
</script> Coming back to your issue, you might think that we then should just pause reactivity tracking while running a ref function. but then, you could not i.e. have a Another way to deal with this is to mark the array to be non-reactive ( So I would say that this is not a bug, and rather something we should document better. |
Thanks @LinusBorg and please excuse any ignorance on my part. Here's what's confusing me:
I gave the example using the options API because we're heavily invested in that for our app, and refactoring everything into the composition API would be a lot of work. But for the demo I gave above I can show that it works using the composition API without throwing the recursive error. In your example it's clear what's causing the recursive render, but my biggest question is why would/should a console.log force a reactive change in the above scenario? That's why it felt like a bug to me. Thanks! 🙂 |
Without the console.log, your template has no dependency on But when you do the console log ( which happens during the render phase), you access the arr.length, which means, the length of the array is now a dependency of your render function, and changing the arrays length will therefore cause a re-render. In short, the console.log in the template ref function has the same effect as if you did: <div :ref="(el) => arr.push(el) ">
{{ arr.length }}
</div> ... you are both mutating a reactive array and read from it in the template, so to speak, leading to an endless re-render loop. If you want feedback on the composition variation of your example, please share it. |
For this use case: <div :ref="(el) => arr.push(el) ">
{{ arr.length }}
</div> Because the above code does not work, I'm thinking if users just want to do this, then what is the correct way 🤔 |
use a non-reactive array, and do any effects in |
<div :ref="setItemRef" v-for="i in 3" :key="i"></div> const itemRefs = reactive<any>([])
const setItemRef = (el: any) => {
if (el) {
itemRefs.push(el)
}
console.log(itemRefs.length)
}
return {
setItemRef
} this also not work |
The cause is that, btw, IIRC, in vue2, ref is non-reactive. |
Version
3.0.11
Reproduction link
See here
Steps to reproduce
Self evident, causes "Uncaught (in promise) Error: Maximum recursive updates exceeded". Comment out or remove the 'console.log' line fixes the issue.
What is expected?
No error
What is actually happening?
Array length increases until maximum recursion limit, throwing 'maximum recursive update exceeded' exception.
The text was updated successfully, but these errors were encountered: