-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
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
Support more collection data types in v-for #2410
Comments
A duplicate of #1319 @wenLiangcan , you could use something like this: <ul>
<li v-for="[key, val] of get(map)">{{key}} - {{val}}</li>
</ul> where |
haha! similar issues open all the time and and people insist that they cannot justify implementation well people want to use it that's one justification I can also list the bazillion of issues closed that ask the same thing xD. I also found one that justifies the use-case really well and refers to es6 specification when it comes to map order ->still closed. |
People wanting to use a feature is not, only by itself, an argument that can justify the need of having such feature, it's necessary to weigh the cost and benefits (what problem is being solved) of adding such feature |
Yep but still the arguments that people use to close the issue are still not valid or at least not valid for all usecases eg the example of the elipen who justified his usecases very well as I mentioned above |
If you want to discuss a specific issue, link to it please. Plus, this Feature issue is open. It does not make sense to have more than one issue open for the same request. |
It's important to be able to iterate over iterators in loops. That seems plainly obvious. It's a fundamental feature of the language. The reasons for supporting it are:
|
Since #1319 is closed, it's worth reiterating on current decision here. In short, the feature is not trivial to implement (on observation mechanism level), so it's not about justifying use cases, it's about the amount of work and trade-offs. I would really appreciate this feature, too. On the other hand, if observing ES6 data types becomes terribly hacky or, for example, compromise performance or other qualities, then people who do not currently use Maps and Sets with Vue might not appreciate this change. |
I suppose using Array.from() inside a computed function will have to be your best friend for now. 😞 |
Any solution for that? |
Small update, this will come if/when Vue decides to drop "legacy" browsers and will move to Evergreen ones with @alexsandro-xpt, just use a computed function that returns |
@nickmessing I try with Map, doesn't work. |
Just As mentioned earlier, Sets and Maps are not observable by Vue. In order to use those — either in data() {
mySetChangeTracker: 1,
mySet: new Set(),
},
computed: {
mySetAsList() {
// By using `mySetChangeTracker` we tell Vue that this property depends on it,
// so it gets re-evaluated whenever `mySetChangeTracker` changes
return this.mySetChangeTracker && Array.from(this.mySet);
},
},
methods: {
add(item) {
this.mySet.add(item);
// Trigger Vue updates
this.mySetChangeTracker += 1;
}
} This illustrates a kinda hacky but 100% working method for making non-observable data reactive. Still, in real world cases I ended up with serialized versions of Sets/Maps (e.g. you'd probably want to store the modified versions of sets/maps in localstorage and thus serialize them anyway), so no artificial counters/hacks were involved. I personally think this is a fair solution to a problem, but it definitely deserves some official documentation — otherwise it's impossible to justify this as non-hacky way of dealing with Vue internals. |
@alexsandro-xpt, sorry, I was wrong, computed will be hacky as @inca said, another hacky solution would be using |
Thank you @nickmessing and @inca, this work fine with my |
Right now when you do a "v-for" over a "Map", the v-for acts as if it had received an empty array. Regardless of the outcome of the extended discussion about whether/how to support Maps and Sets, it would save a lot of people a lot of debugging time if Vue simply warned "Maps and Sets are not yet supported -- see #2410". |
Yup, Google search for this feature brought me to this ticket (after a few annoying mixups with Vue.set) 👍 This should be in the v-for documentation! |
Truly, should be in v-for documentation! |
/cc @chrisvfritz let's try to add a note about support for these types up in the docs for |
@yyx990803 I wonder if a console warning would be better for this, since that would tell people what's wrong immediately, obviating the need to search for the solution. We're also already very explicit in the docs about which types we do support, |
I'm not quite seeing the argument against adding support for
|
My best guess (please correct/sorry if I'm wrong): the trickiest part is to wrap a |
The current problem with the Vue.set method on a plain object is that it triggers way too many subscribers when a property is added to the object. Actually, all the subscribers of all the properties are triggered when only one property is added. The performance of the view is badly impacted when a map like collection contains hundredth of keys. For example, in my project thousands of subscribers are triggered when one element is added to the map using the Vue.set operation:
When I look deeply into the Vue.js code, I can see where the problem comes from. The dependencies that are triggered are those of the object, which means that if the object has one property for each key, then all the dependencies of all the keys are triggered when just adding one key. So using plain objects to mimic a map does not look as the right solution, and therefore having support for a map in vue is more than welcomed for large collections of items. |
Is there any news about future plans and possibly about native |
This article details upcoming support in 2.6 - but there's nothing about that in the official roadmap from what I can see?
Not sure where they got that information from? |
Found this issue while was debugging the heck Vue's behavior over |
For people like me that were wondering about the roadmap for this, Evan You says in this video that Map and Set support is "likely" to arrive in 2.6, but that was in May, so that's all I know. |
@yyx990803 It's unfortunate that this issue in the tracker is marked as closed, especially if you're considering adding support in the near future. Where can we follow progress on this feature? Is there another issue somewhere? |
Just wondering for the sake of argument, and maybe I am doing it wrong, but since you can track array mutation using the Mutation Methods cant you just track an array of an object and be logically complete? you dont get all the same features implemented in Map but the ones you want would be pretty easily addressed especially if you are using something like _ or lodash. |
Its sad but until the team adds this we might have to use alternate data structures |
Just want to chime in that we were going to use a Map for our data structure, then decided against it because of a lack of first-party support. |
This is planned for vue.js v3.0. |
Solution: github.com/vuejs/vue/issues/2410#issuecomment-318487855
is this supported now in Vue3 (that is, reactive |
any updates ? |
I can confirm that |
I've tested Maps for reactivity as well and they work. In particular (for my use case), calls to computed functions that use I'll add that I love Maps and use them a lot. They are much more efficient than Object-based dictionaries, especially when working with integer keys. Plus they allow indexing on object references, which can't be done with Objects. I like to use them for managing aggregated data that is useful in various places in the app. Very happy to see that this is implemented! |
Using @vue/composition-api I have come up with the following solution for Vue 2. // useReactiveSet.ts
import { ref, computed } from '@vue/composition-api'
export default function useReactiveSet<T>() {
const version = ref(1)
class ReactiveSet extends Set<T> {
add(value: T) {
super.add(value)
version.value += 1
return this
}
}
const inner = ref(new ReactiveSet())
const set = computed(() => {
version.value
return inner.value
})
return set
} // Component.vue
{
// ...
setup() {
const set = useReactiveSet<number>()
setTimeout(() => {
// this will trigger rerender
set.value.add(2)
}, 1000)
return {
set,
}
},
// ...
} You can use the same approach for |
@inca I have created a package that was adopted from your comment. Thank you so much! https://github.com/bluecanvas/vue-reactive-collection |
这是来自QQ邮箱的假期自动回复邮件。
您好,我现在没在上网,无法亲自回复您的邮件。我会在上网后,尽快给您回复。
|
It works by assigning new clone with property changes.
|
这是来自QQ邮箱的假期自动回复邮件。
您好,我现在没在上网,无法亲自回复您的邮件。我会在上网后,尽快给您回复。
|
At some situations, plain object isn't the best choise. I tried to render a
Map
object byv-for
, but seemsVue
does not support it currently. (Here's a post I created in the Help thread on the forum.)Hope
Vue
can provide thefor ... of
syntax inv-for
to iterate over data types likeMap
andSet
.For example:
and we can render
map
in this way:The text was updated successfully, but these errors were encountered: