core icon indicating copy to clipboard operation
core copied to clipboard

sometimes template can not apply key by v-for

Open yoyo837 opened this issue 2 years ago • 12 comments

Link to minimal reproduction

https://stackblitz.com/edit/vue3-forwarding-slots-qmswhv?file=src%2FApp.vue,src%2Fcomponents%2FComponentA.vue

Steps to reproduce

None.

What is expected?

Works.

What is actually happening?

It report error.

image

System Info

System:
    OS: macOS 12.3.1
    CPU: (10) arm64 Apple M1 Max
    Memory: 2.97 GB / 32.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 16.15.0 - /opt/homebrew/opt/node@16/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 8.5.5 - /opt/homebrew/opt/node@16/bin/npm
  Browsers:
    Chrome: 101.0.4951.64
    Firefox: 100.0.1
    Safari: 15.4

Any additional comments?

See https://github.com/vuejs/core/discussions/5962.

yoyo837 avatar May 20 '22 03:05 yoyo837

Moving the :key binding from <template> to <slot> resolves the issue:

<van-loading>
  <template v-for="(_, slot) of $slots" v-slot:[slot]="scope">
                                         👇
    <slot :name="slot" v-bind="scope" :key="slot" />
  </template>
</van-loading>

demo

tony19 avatar May 20 '22 04:05 tony19

Moving the :key binding from <template> to <slot> resolves the issue:

<van-loading>
  <template v-for="(_, slot) of $slots" v-slot:[slot]="scope">
                                         👇
    <slot :name="slot" v-bind="scope" :key="slot" />
  </template>
</van-loading>

demo

Thanks for your quick reply.

Please look at componentB in the copied link, is this another problem?

yoyo837 avatar May 20 '22 06:05 yoyo837

It seems that adding key can also be solved, but there is no v-for here.

yoyo837 avatar May 20 '22 06:05 yoyo837

Your usage in that blitz doesn't make sense to me. To forward the default slot, just use <slot/>:

<template>
  <van-loading v-bind="$attrs">
    <slot />
  </van-loading>
</template>

demo

tony19 avatar May 20 '22 06:05 tony19

Thanks for your help, adding the key to the slot solved my problem, there's only one lint error left that confuses me. https://github.com/vuejs/eslint-plugin-vue/issues/1900 I disabled the rule to make it works.

yoyo837 avatar May 20 '22 06:05 yoyo837

Not sure about the key issue. I'm wondering if <template>'s key is supposed to be automatically applied to <slot> children. Nothing in the docs suggests the key should be manually/explicitly moved to the children, so it might be a Vue bug after all (not a linter bug). 🤔

tony19 avatar May 20 '22 06:05 tony19

Not sure about the key issue. I'm wondering if <template>'s key is supposed to be automatically applied to <slot> children. Nothing in the docs suggests the key should be manually/explicitly moved to the children, so it might be a Vue bug after all (not a linter bug). 🤔

So do you think this needs to be fixed in vue? Alternatively, others who got this error should also take the solution you gave me as the final solution?

yoyo837 avatar May 20 '22 06:05 yoyo837

So do you think this needs to be fixed in vue?

Yes, I think so. But the template in the original repro is invalid IMO (see comment). I recommend creating a new issue with valid markup that generates the error.

Alternatively, others who got this error should also take the solution you gave me as the final solution?

Assuming the key issue is indeed a Vue bug, adding the key binding to the <slot> (and disabling the linter warning for those lines only) is a reasonable workaround for the time being.

tony19 avatar May 20 '22 07:05 tony19

Yes, I think so. But the template in the original repro is invalid IMO (see comment). I recommend creating a new issue with valid markup that generates the error.

I've updated it https://stackblitz.com/edit/vue3-forwarding-slots-qmswhv?file=src%2FApp.vue,src%2Fcomponents%2FComponentA.vue

yoyo837 avatar May 20 '22 07:05 yoyo837

any update on this ?
I have this code part of a Vue 3 migration :

<template>
  <v-card
    rounded="0"
    :loading="loading"
  >
    <v-card-title>
      Exécutions
    </v-card-title>
    <v-list class="py-0">
      <template v-if="runs">
        <template v-for="run in runs.results">
          <v-divider :key="run._id + '-divider'" />
          <run-list-item
            :key="run._id + '-item'"
            :run="run"
            :link="true"
            :can-exec="canExec"
          />
        </template>
      </template>
    </v-list>
  </v-card>
</template>

indeed, eslint-plugin-vue triggers : <template v-for> key should be placed on the <template> tag
but when I change it, it triggers again : '<template v-for>' cannot be keyed. Place the key on real elements instead
I'm perplex

EDM115 avatar Feb 29 '24 08:02 EDM115

@EDM115 That's not related to this issue.

Your problem is that your eslint config has two rules active that are incompatible.

The first error is from the Vue 3 rule: https://eslint.vuejs.org/rules/no-v-for-template-key-on-child.html#vue-no-v-for-template-key-on-child

The second error is from the Vue 2 rule: https://eslint.vuejs.org/rules/no-v-for-template-key.html

So the solution would be to disable one of them - likely the second one as you are on Vue 3 now.

LinusBorg avatar Feb 29 '24 09:02 LinusBorg

indeed, there was an oversight in my eslint config
thanks, this was driving me insane :)

EDM115 avatar Feb 29 '24 09:02 EDM115