Subscribe on changes!

sometimes template can not apply key by v-for

avatar
May 20th 2022

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.

avatar
May 20th 2022

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

avatar
May 20th 2022

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?

avatar
May 20th 2022

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

avatar
May 20th 2022

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

avatar
May 20th 2022

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.

avatar
May 20th 2022

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

avatar
May 20th 2022

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?

avatar
May 20th 2022

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.

avatar
May 20th 2022

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

avatar
Feb 29th 2024

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

avatar
Feb 29th 2024

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

avatar
Feb 29th 2024

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