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

[Proposal] Allow single-element exception for vue/require-v-for-key #2512

Open
matthew-dean opened this issue Jul 20, 2024 · 2 comments
Open

Comments

@matthew-dean
Copy link

matthew-dean commented Jul 20, 2024

What rule do you want to change?
vue/require-v-for-key

Context
It's a useful pattern to bind an object within a larger object to the scope of Vue markup to reduce code. There really is no mechanism for this in Vue except for v-for. v-for (+ Vue Language Services) scopes a variable based on how it interprets the result of the v-for statement. Because of this, you can essentially reduce boilerplate and, in some cases, slightly speed up performance by using v-for.

Consider this example where getTyped is something like Lodash's get, but providing this specific path in the following example returns a strongly-typed object with the shape of:

Reactive<{
  value: string
  error: string | undefined
}>
    <input v-model="getTyped(model, 'a.deeply.bound.path.name').value" />
    <div v-if="getTyped(model, 'a.deeply.bound.path.name').error">
      {{ getTyped(model, 'a.deeply.bound.path.name').error }}
    </div>

This is, of course, ugly and verbose. A nifty way to clean it up for a template binding would be to do this:

  <template v-for="name in [getTyped(model, 'a.deeply.bound.path.name')]">
    <input v-model="name.value" />
    <div v-if="name.error">
      {{ name.error }}
    </div>
  </template>

TypeScript / Volar respects this immediately, and we get a strong typing for name as expected. However, eslint-plugin-vue (with this rule) immediately complains. In this case, though, it doesn't need to. While the Vue docs recommend a key for v-for, the above example is easily parseable to be understood as a tuple constant with one element, and there are no key issues when only ever iterating from one element. There will only ever be one element, so the key is not needed.

Does this change cause the rule to produce more or fewer warnings?
Fewer

How will the change be implemented? (New option, new default behavior, etc.)?
New option:

'vue/require-v-for-key': ['error', {
  allowSingleElement: true
}]

Please provide some example code that this change will affect:

<div v-for="name in [get(model, 'a.deeply.bound.model')]">
    <input v-model="name.value" />
    <div test-id="name">
      {{ name.error }}
    </div>
  </div>

What does the rule currently do for this code?
It throws an error if key is absent.

What will the rule do after it's changed?
The rule will behave the same by default. If allowSingleElement is set to true, it throws an error if key is absent, except when v-for refers only to a tuple with a single element / item.

Thanks for considering!

@matthew-dean
Copy link
Author

Just a little bit more context. I took a look at Vue's documentation, and it has this to say (emphasis mine):

It is recommended to provide a key attribute with v-for whenever possible, unless the iterated DOM content is simple (i.e. contains no components or stateful DOM elements), or you are intentionally relying on the default behavior for performance gains.

I believe that this change would conform entirely to the documentation, as this use-case is, by definition, simple.

@FloEdelmann
Copy link
Member

the iterated DOM content is simple (i.e. contains no components or stateful DOM elements)

Your examples are not "simple" in the mentioned sense though, as you have an <input> in the iterated content, which is a stateful DOM element.

However, regarding your proposal: I'm not sure whether we should endorse this behavior by adding an option for it. Using v-for with only a single array item is a hacky workaround for a template variable. Why not use a computed variable for it? And if it's inside of a ("real") v-for loop, then maybe it would rather make sense to extract that loop content into a separate component, where you could use a computed variable again.

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

No branches or pull requests

2 participants