Vue: Admite más tipos de datos de recopilación en v-for

Creado en 28 feb. 2016  ·  39Comentarios  ·  Fuente: vuejs/vue

En algunas situaciones, el objeto simple no es la mejor opción. Intenté renderizar un objeto Map por v-for , pero parece que Vue no lo admite actualmente. (Aquí hay una publicación que creé en el hilo de ayuda del foro).

Espero que Vue pueda proporcionar la sintaxis for ... of en v-for para iterar sobre tipos de datos como Map y Set .

Por ejemplo:

const map = new Map();
map.set('key1', 'val1');
map.set('key2', 'val2');

y podemos renderizar map de esta manera:

<ul>
    <li v-for="[key, val] of map">{{key}} - {{val}}</li>
</ul>
feature request

Comentario más útil

Es importante poder iterar sobre iteradores en bucles. Eso parece claramente obvio. Es una característica fundamental del idioma.

Las razones para apoyarlo son:

1) Los iteradores, mapas y conjuntos son todos ES6 válidos. Negarse a apoyarlos significa limitarse a ES5, que es una decisión cada vez menos justificada con el tiempo.
2) Estoy creando una aplicación que tiene datos internos almacenados en mapas y conjuntos. En lugar de ponerlos a disposición de la interfaz de usuario, ahora necesito mantener los datos sincronizados entre los dos manualmente, o escribir un texto estándar e importarlo a mis plantillas para realizar la conversión siempre que se necesiten los datos. Esto es exactamente lo que Vue pretende evitar.

Todos 39 comentarios

Un duplicado de https://github.com/vuejs/vue/issues/1319

@wenLiangcan , podrías usar algo como esto:

<ul>
    <li v-for="[key, val] of get(map)">{{key}} - {{val}}</li>
</ul>

donde get() es su función.

¡ja ja! problemas similares se abren todo el tiempo y la gente insiste en que no pueden justificar la implementación bien, la gente quiere usarla, esa es una justificación. También puedo enumerar los millones de problemas cerrados que piden lo mismo xD. También encontré uno que justifica el caso de uso realmente bien y se refiere a la especificación es6 cuando se trata del orden del mapa -> aún cerrado.

Que las personas quieran utilizar una característica no es, solo por sí mismo, un argumento que pueda justificar la necesidad de tener dicha característica, es necesario sopesar el costo y los beneficios (qué problema se está resolviendo) de agregar dicha característica.

Sí, pero los argumentos que la gente usa para cerrar el problema aún no son válidos o al menos no son válidos para todos los casos de uso, por ejemplo, el ejemplo del elipen que justificó muy bien sus casos de uso como mencioné anteriormente.

Si desea discutir un tema específico, enlace a él.

Además, el problema de esta función está abierto. No tiene sentido tener más de un problema abierto para la misma solicitud.

Es importante poder iterar sobre iteradores en bucles. Eso parece claramente obvio. Es una característica fundamental del idioma.

Las razones para apoyarlo son:

1) Los iteradores, mapas y conjuntos son todos ES6 válidos. Negarse a apoyarlos significa limitarse a ES5, que es una decisión cada vez menos justificada con el tiempo.
2) Estoy creando una aplicación que tiene datos internos almacenados en mapas y conjuntos. En lugar de ponerlos a disposición de la interfaz de usuario, ahora necesito mantener los datos sincronizados entre los dos manualmente, o escribir un texto estándar e importarlo a mis plantillas para realizar la conversión siempre que se necesiten los datos. Esto es exactamente lo que Vue pretende evitar.

Dado que el # 1319 está cerrado, vale la pena reiterar la decisión actual aquí. En resumen, la función no es trivial de implementar (a nivel de mecanismo de observación), por lo que no se trata de justificar casos de uso, se trata de la cantidad de trabajo y las compensaciones.

También agradecería mucho esta función. Por otro lado, si la observación de los tipos de datos de ES6 se vuelve terriblemente hacky o, por ejemplo, compromete el rendimiento u otras cualidades, entonces las personas que actualmente no usan Mapas y Conjuntos con Vue podrían no apreciar este cambio.

Supongo que usar Array.from () dentro de una función calculada tendrá que ser tu mejor amigo por ahora. :decepcionado:

¿Alguna solución para eso?

Pequeña actualización, esto vendrá si / cuando Vue decida eliminar los navegadores "heredados" y pasará a los de Evergreen con Proxy lugar de set / get por reactividad.

@ alexsandro-xpt, simplemente use una función calculada que devuelva Array.from(yourDataSet) .

@nickmessing Lo intento con Map, no funciona.
El valor de la longitud de la matriz calculada es siempre 0.

Solo Array.from probablemente no sea la solución que desea debido a la falta de reactividad (los cambios a yourDataSet no se propagarán a Vue).

Como se mencionó anteriormente, los conjuntos y mapas no son observables por Vue. Para usarlos, ya sea en v-for , o en propiedades calculadas, métodos, observadores, expresiones de plantilla, etc., debe crear una réplica serializable de esta estructura y exponerla a Vue. Aquí hay un ejemplo ingenuo que usa un contador simple para proporcionar a Vue información de que Set está actualizado:

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;
  }
}

Esto ilustra un método un poco hacky pero 100% de trabajo para hacer que los datos no observables sean reactivos. Aún así, en los casos del mundo real terminé con versiones serializadas de Conjuntos / Mapas (por ejemplo, probablemente querrías almacenar las versiones modificadas de conjuntos / mapas en el almacenamiento local y así serializarlas de todos modos), por lo que no se involucraron contadores / hacks artificiales.

Personalmente, creo que esta es una solución justa para un problema, pero definitivamente merece algo de documentación oficial; de lo contrario, es imposible justificar esto como una forma no pirateada de tratar con los componentes internos de Vue.

@ alexsandro-xpt, lo siento, estaba equivocado, el cálculo será hacky como dijo @inca , otra solución hacky sería usar $forceUpdate con un método, aquí hay un ejemplo de violín

Gracias @nickmessing y @inca , esto funciona bien con mi new Map() !!

Ahora mismo, cuando hace una "v-for" sobre un "Map", la v-for actúa como si hubiera recibido una matriz vacía.

Independientemente del resultado de la discusión extendida sobre si y cómo admitir mapas y conjuntos, a mucha gente le ahorraría mucho tiempo de depuración si Vue simplemente advirtiera "Los mapas y conjuntos aún no son compatibles; consulte https: // github .com / vuejs / vue / issues / 2410 ".

Sí, la búsqueda en Google de esta función me llevó a este ticket (después de algunas confusiones molestas con Vue.set)

👍 ¡Esto debería estar en la documentación de v-for!

¡Realmente, debería estar en documentación v-for!

/ cc @chrisvfritz intentemos agregar una nota sobre el soporte para estos tipos en los documentos por v-for (tanto la API como la sección de representación de listas); también las veré en 2.5.

@ yyx990803 Me pregunto si una advertencia de consola sería mejor para esto, ya que le diría a la gente lo que está mal de inmediato, evitando la necesidad de buscar la solución.

También somos muy explícitos en los documentos acerca de qué tipos _admitimos_, Map y Set no están entre ellos. Definitivamente puedo ver el argumento de por qué uno podría _esperar_ que todos los iterables funcionen con v-for , pero no creo que actualmente le demos a los lectores ninguna razón para esperar que lo hagan.

No veo el argumento en contra de agregar soporte para Set .

Set sí mismo se puede rellenar limpiamente y, a menos que me falte algo, parece que el enfoque de Vue para agregar reactividad a las matrices podría extenderse muy fácilmente a los conjuntos. Solo necesitaríamos envolver .add() , .clear() y .delete() .

Mi mejor suposición (corrija / disculpe si me equivoco): la parte más complicada es envolver un constructor Set , que acepta un iterable. No veo cómo iterable puede hacerse observable, porque en su forma general es solo una función (es decir, next ) sin un estado referenciable (piense en un iterador basado en generador como ejemplo).

¿Por qué necesitamos envolver el constructor? ¿No pasaríamos Sets preexistentes a Vue?

De acuerdo con la especificación , el constructor Set se ejecuta inmediatamente a través de todo el iterador, reteniendo efectivamente una copia superficial de los elementos únicos devueltos por el iterador. Una vez que tenga una instancia Set , no debería importar si se creó a partir de un iterador o no.

En este sentido, un Set creado a partir de un iterador no debería ser diferente de una matriz creada a partir de un iterador (a través de Array.from() ), que Vue ya admite.

Sin embargo, puede usar Mapas / conjuntos / cualquier estructura de datos inmutable y permitir la reactividad con ellos, pero simplemente porque cambia toda la referencia. Puede renderizarlos a través de una función de renderizado o una matriz generada calculada (cuanto antes sea mejor en rendimiento, ya que omite la creación de una matriz ..). Pero las estructuras de datos mutables, no es así a menos que encuentre una manera de notificar a Vue de cambios específicos manualmente, lo que sería simplemente preparar su propia solución.

Eso no es bueno. No puedes hacerlo

@wenLiangcan

var map = new Map()
  map.set('key1','Test1')
  map.set('key2','Test2')
        <div class="file-size">{{value}}</div>
 </div>

No, no aparece en la página.

Deseoso de apoyar esto :)

Yo también

¿Algún plan futuro para agregar soporte? ¿Existe alguna razón técnica por la que Vue no sea compatible con Map and Set?

El problema actual con el método Vue.set en un objeto simple es que activa demasiados suscriptores cuando se agrega una propiedad al objeto. En realidad, todos los suscriptores de todas las propiedades se activan cuando solo se agrega una propiedad.

El rendimiento de la vista se ve gravemente afectado cuando un mapa como una colección contiene una centésima parte de claves. Por ejemplo, en mi proyecto, miles de suscriptores se activan cuando se agrega un elemento al mapa usando la operación Vue.set:

Vue.set(state.items, itemId, item); // where items is a plain object.

Cuando miro profundamente en el código de Vue.js, puedo ver de dónde viene el problema. Las dependencias que se activan son las del objeto, lo que significa que si el objeto tiene una propiedad para cada clave, entonces todas las dependencias de todas las claves se activan con solo agregar una clave.

Por lo tanto, usar objetos simples para imitar un mapa no parece la solución correcta y, por lo tanto, tener soporte para un mapa en vue es más que bienvenido para grandes colecciones de elementos.

¿Hay alguna noticia sobre planes futuros y posiblemente sobre soporte nativo Map/Set ?

Este artículo detalla el próximo soporte en 2.6, pero no hay nada al respecto en la hoja de ruta oficial por lo que puedo ver.

https://medium.com/@alberto.park/the -status-of-javascript-libraries-frameworks-2018-beyond-3a5a7cae7513

"La última versión actual del núcleo es 2.5.x. La próxima versión secundaria (v2.6) admitirá la importación de ESM nativa, el manejo de errores asíncronos mejorado, el iterador en la directiva 'v-for' y más".

¿No estás seguro de dónde sacaron esa información?

Encontré este problema mientras depuraba el comportamiento de Vue sobre los objetos de datos Set . :pensando:

Para las personas como yo que se preguntaban sobre la hoja de ruta para esto, Evan You dice en este video que es "probable" que el soporte de Map and Set llegue en 2.6, pero eso fue en mayo, así que eso es todo lo que sé.

@ yyx990803 Es lamentable que este problema en el rastreador esté marcado como cerrado, especialmente si está considerando agregar soporte en un futuro cercano. ¿Dónde podemos seguir el progreso de esta función? ¿Hay otro problema en alguna parte?

Solo me pregunto por el bien de la discusión, y tal vez lo esté haciendo mal, pero dado que puede rastrear la mutación de matriz utilizando los Métodos de mutación, ¿ no puede simplemente rastrear una matriz de un objeto y estar lógicamente completo? no se implementan las mismas funciones en Map, pero las que desea se abordarán con bastante facilidad, especialmente si está usando algo como _ o lodash.

Es triste, pero hasta que el equipo agregue esto, es posible que tengamos que usar estructuras de datos alternativas

Solo quiero decir que íbamos a usar un mapa para nuestra estructura de datos, luego decidimos no hacerlo debido a la falta de soporte de primera parte.

¿Es esto compatible ahora en Vue3 (es decir, reactivo Map y Set )?

¿Fue útil esta página
0 / 5 - 0 calificaciones