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

Compiler not allowing correct usage of <transition-group> keys #5360

Closed
petterw03 opened this issue Feb 4, 2022 · 5 comments
Closed

Compiler not allowing correct usage of <transition-group> keys #5360

petterw03 opened this issue Feb 4, 2022 · 5 comments

Comments

@petterw03
Copy link

Version

3.2.29

Reproduction link

sfc.vuejs.org/

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.

@lidlanca
Copy link
Contributor

lidlanca commented Feb 4, 2022

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>

@LinusBorg
Copy link
Member

Duplicate of #4718

@LinusBorg LinusBorg marked this as a duplicate of #4718 Feb 4, 2022
@petterw03
Copy link
Author

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).

@lidlanca
Copy link
Contributor

lidlanca commented Feb 4, 2022

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>

@espresso
Copy link

espresso commented Feb 6, 2022

@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:
b0d01e9

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.

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

Successfully merging a pull request may close this issue.

4 participants