Compiler not allowing correct usage of <transition-group> keys
Version
3.2.29
Reproduction link
Steps to reproduce
Open the reproduction code.
What is expected?
Code should compile and transitions should work fluently when clicking the buttons.
What is actually happening?
It will not compile because of the key
property on the group headings:
SyntaxError: <template v-for> key should be placed on the <template> tag.
App.vue
19 | <transition-group name="cell" tag="div" class="grid">
20 | <template v-for="group in groups" :key="group.id">
21 | <h2 :key="`title-${group.id}`">{{ group.name }}</h2>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
22 | <div v-for="letter in group.letters" :key="letter">{{ letter }}</div>
23 | </template>
Removing the key will throw a warning:
at <TransitionGroupname="cell"tag="div"class="grid">
This warning is correct, because without a key the transitions will not work as expected when adding or removing items from the groups
array.
There are a couple of similar issues (#4718, #5152), but they are not duplicates of this one since they are focusing on the warning when a key is not used. But in this case, a key is needed but the code won't compile, even though it is valid code.
possible workaround sfc
<transition-group name="cell" tag="div" class="grid">
<template v-for="group in groups" :key="group.id">
<template v-if=true >
<h2 :key="`title-${group.id}`">{{ group.name }}</h2>
<div v-for="letter in group.letters" :key="letter" class="item">{{ letter }}</div>
</template>
</template>
</transition-group>
Thank you @lidlanca for the workaround, it works well but is indeed a workaround. As already mentioned, this is not a duplicate since the previous issue addresses the console warning - however the console warning isn't a bug but the compiler error is, and it cannot be suppressed or ignored (unlike the warning).
issues are related and revolve around the same base bug
#4718 expects that there will be no warning, since the fragment is keyed, and it doesn't try to key the fragment nodes. #5360 based on the same warning, try to address it, by keying individual fragment nodes manually, but fail due to syntax error
However this issue exposes an additional bug
There is technically no reason for key
in a child node of a v-for
fragment to be considered a syntax error.
especially for multi nodes fragment
this should be valid code
<template v-for="item in items" :key="item.i">
<h1>chart</h1>
<chart :key="refresh[item.id]"></chart>
</template>
independent of <transition-group>
@LinusBorg
I've been able to remedy this issue by removing the block of code that validates this specific condition.
Line 155 of errors.ts:
[ErrorCodes.X_V_FOR_TEMPLATE_KEY_PLACEMENT]: `<template v-for> key should be placed on the <template> tag.`,
Line 121 of vFor.ts:
// check <template v-for> key placement
if ((__DEV__ || !__BROWSER__) && isTemplate) {
node.children.some(c => {
if (c.type === NodeTypes.ELEMENT) {
const key = findProp(c, 'key')
if (key) {
context.onError(
createCompilerError(
ErrorCodes.X_V_FOR_TEMPLATE_KEY_PLACEMENT,
key.loc
)
)
return true
}
}
})
}
Before I make a PR, I just wanted to confirm that this is actually an issue and that simply removing this code is a satisfactory solution.
It looks like this was intentionally added by @yyx990803 back in 2020: https://github.com/vuejs/core/commit/b0d01e9db9ffe5781cce5a2d62c8552db3d615b0
dx(compiler-core): warn on key misplacement Note: the behavior is different from Vue 2.
<template v-for>
are compiled into an array of Fragment vnodes so the key should be placed the<template>
for v-for to use it for diffing.