Vue: Suporta mais tipos de coleta de dados em v-for

Criado em 28 fev. 2016  ·  39Comentários  ·  Fonte: vuejs/vue

Em algumas situações, o objeto simples não é a melhor escolha. Tentei renderizar um objeto Map por v-for , mas parece que Vue não o suporta atualmente. (Aqui está uma postagem que criei no tópico de Ajuda do fórum.)

Espero que Vue possa fornecer a sintaxe for ... of em v-for para iterar sobre tipos de dados como Map e Set .

Por exemplo:

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

e podemos renderizar map desta forma:

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

Comentários muito úteis

É importante poder iterar sobre iteradores em loops. Isso parece completamente óbvio. É uma característica fundamental da linguagem.

As razões para apoiá-lo são:

1) Iteradores, mapas e conjuntos são todos ES6 válidos. Recusar-se a apoiá-los significa limitar-se ao ES5, que é uma decisão que se torna cada vez menos justificada com o tempo.
2) Estou construindo um aplicativo que possui dados internos armazenados em Mapas e Conjuntos. Em vez de disponibilizá-los para a IU, agora preciso manter os dados sincronizados entre os dois manualmente ou escrever um texto padronizado e importá-lo para meus modelos para fazer a conversão sempre que os dados forem necessários. Isso é exatamente o que Vue pretende evitar.

Todos 39 comentários

Uma duplicata de https://github.com/vuejs/vue/issues/1319

@wenLiangcan , você poderia usar algo assim:

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

onde get() é a sua função.

haha! questões semelhantes abrem o tempo todo e as pessoas insistem que não podem justificar bem a implementação, as pessoas querem usá-la. Essa é uma justificativa. Também posso listar o bazilhão de questões fechadas que perguntam a mesma coisa xD. Eu também encontrei um que justifica muito bem o caso de uso e se refere à especificação es6 quando se trata de ordem do mapa -> ainda fechado.

Quem quer usar um recurso não é, por si só, um argumento que pode justificar a necessidade de tal recurso, é preciso pesar o custo e os benefícios (qual problema está sendo resolvido) de adicionar tal recurso

Sim, mas os argumentos que as pessoas usam para fechar o problema ainda não são válidos ou pelo menos não são válidos para todos os casos de uso, por exemplo, o exemplo do elipen que justificou seus casos de uso muito bem como mencionei acima

Se você quiser discutir um assunto específico, conecte-se a ele.

Além disso, este problema de recurso está aberto. Não faz sentido ter mais de um problema aberto para a mesma solicitação.

É importante poder iterar sobre iteradores em loops. Isso parece completamente óbvio. É uma característica fundamental da linguagem.

As razões para apoiá-lo são:

1) Iteradores, mapas e conjuntos são todos ES6 válidos. Recusar-se a apoiá-los significa limitar-se ao ES5, que é uma decisão que se torna cada vez menos justificada com o tempo.
2) Estou construindo um aplicativo que possui dados internos armazenados em Mapas e Conjuntos. Em vez de disponibilizá-los para a IU, agora preciso manter os dados sincronizados entre os dois manualmente ou escrever um texto padronizado e importá-lo para meus modelos para fazer a conversão sempre que os dados forem necessários. Isso é exatamente o que Vue pretende evitar.

Visto que o # 1319 está fechado, vale a pena reiterar a decisão atual aqui. Resumindo, o recurso não é trivial de implementar (no nível do mecanismo de observação), então não se trata de justificar casos de uso, é sobre a quantidade de trabalho e compensações.

Eu realmente aprecio esse recurso também. Por outro lado, se observar os tipos de dados ES6 se tornar terrivelmente hackeado ou, por exemplo, comprometer o desempenho ou outras qualidades, então as pessoas que não usam Mapas e Conjuntos com Vue podem não apreciar esta mudança.

Suponho que usar Array.from () dentro de uma função computada será seu melhor amigo por enquanto. : desapontado:

Alguma solução para isso?

Esta pequena atualização virá se / quando Vue decidir descartar os navegadores "legados" e passar para os Evergreen com Proxy vez de set / get para reatividade.

@ alexsandro-xpt, basta usar uma função computada que retorna Array.from(yourDataSet) .

@nickmessing que tento com o Map, não funciona.
O valor calculado do comprimento da matriz é sempre 0.

Apenas Array.from provavelmente não é a solução desejada por causa da falta de reatividade (alterações em yourDataSet não serão propagadas para Vue).

Como mencionado anteriormente, Conjuntos e Mapas não são observáveis ​​por Vue. Para usá-los - em v-for , ou em propriedades computadas, métodos, observadores, expressões de modelo, etc. - você precisa criar uma réplica serializável desta estrutura e expô-la ao Vue. Aqui está um exemplo ingênuo que usa um contador simples para fornecer à Vue informações de que Set foi atualizado:

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

Isso ilustra um método meio hacky, mas 100% funcional, para tornar reativos os dados não observáveis. Ainda assim, em casos do mundo real acabei com versões serializadas de Conjuntos / Mapas (por exemplo, você provavelmente gostaria de armazenar as versões modificadas de conjuntos / mapas no armazenamento local e, assim, serializá-los de qualquer maneira), então nenhum contador / hack artificial foi envolvido.

Eu pessoalmente acho que esta é uma solução justa para um problema, mas definitivamente merece alguma documentação oficial - caso contrário, é impossível justificar isso como uma forma não hacky de lidar com os componentes internos do Vue.

@ alexsandro-xpt, desculpe, eu estava errado, computado será hacky como @inca disse, outra solução hacky seria usar $forceUpdate com um método, aqui está um exemplo de violino

Obrigado @nickmessing e @inca , funcionou bem com meu new Map() !!

Agora, quando você faz um "v-for" sobre um "Mapa", o v-for age como se tivesse recebido um array vazio.

Independentemente do resultado da longa discussão sobre se / como oferecer suporte a Mapas e Conjuntos, muitas pessoas economizariam muito tempo de depuração se Vue simplesmente avisasse "Mapas e Conjuntos ainda não são compatíveis - consulte https: // github .com / vuejs / vue / issues / 2410 ".

Sim, a pesquisa no Google por esse recurso me trouxe a este tíquete (depois de alguns confusões irritantes com Vue.set)

👍 Isso deve estar na documentação v-for!

Na verdade, deve estar em v para documentação!

/ cc @chrisvfritz vamos tentar adicionar uma nota sobre o suporte para esses tipos na documentação de v-for (API e a seção de renderização de lista) - também irei dar uma olhada neles em 2.5.

@ yyx990803 Eu me pergunto se um aviso do console seria melhor para isso, já que diria às pessoas o que está errado imediatamente, evitando a necessidade de procurar a solução.

Também já estamos muito explícitos nos documentos sobre quais tipos nós _do_ suportamos, Map e Set não estando entre eles. Eu posso definitivamente ver o argumento de por que alguém pode _esperar_ que todos os iteráveis ​​funcionem com v-for , mas não acho que atualmente damos aos leitores qualquer razão para esperar que funcionem.

Não estou entendendo bem o argumento contra a adição de suporte para Set .

Set si pode ser polifilhado de forma limpa e, a menos que esteja faltando alguma coisa, parece que a abordagem de Vue para adicionar reatividade a matrizes poderia facilmente ser estendida a conjuntos. Só precisaríamos embrulhar .add() , .clear() e .delete() .

Meu melhor palpite (corrija / desculpe se eu estiver errado): a parte mais complicada é embrulhar um construtor Set , que aceita um iterável. Não vejo como iterável pode ser tornado observável, porque em sua forma geral é apenas uma função (ou seja, next ) sem estado referenciável (pense no iterador baseado em gerador como um exemplo).

Por que precisamos envolver o construtor? Não estaríamos passando Sets pré-existentes para o Vue?

De acordo com a especificação , o construtor Set passa imediatamente por todo o iterador, retendo efetivamente uma cópia superficial dos itens exclusivos retornados pelo iterador. Depois de obter uma instância Set , não importa se ela foi criada a partir de um iterador ou não.

A este respeito, um Set criado a partir de um iterador não deve ser diferente de um array criado a partir de um iterador (via Array.from() ), que o Vue já suporta.

Você pode usar mapas / conjuntos / qualquer estrutura de dados imutáveis ​​e permitir reatividade com eles, mas simplesmente porque toda a referência do bloco muda. Você pode renderizá-los por meio de uma função de renderização ou array gerado computado (o anterior sendo melhor em desempenho, pois ignora a criação de um array ..). Mas estruturas de dados mutáveis ​​não são assim, a menos que você encontre uma maneira de notificar o Vue sobre mudanças específicas manualmente, o que seria simplesmente criar sua própria solução.

Isso não é bom. Você não pode fazer isso

@wenLiangcan

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

Não, não aparece na página

Ansioso por apoiar isto:)

Eu também

Algum plano futuro para adicionar suporte? Há algum motivo técnico para o Vue não suportar Map and Set?

O problema atual com o método Vue.set em um objeto simples é que ele dispara muitos assinantes quando uma propriedade é adicionada ao objeto. Na verdade, todos os assinantes de todas as propriedades são acionados quando apenas uma propriedade é adicionada.

O desempenho da visualização é fortemente afetado quando uma coleção do tipo mapa contém um centésimo de chaves. Por exemplo, em meu projeto, milhares de assinantes são acionados quando um elemento é adicionado ao mapa usando a operação Vue.set:

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

Quando examino profundamente o código Vue.js, posso ver de onde vem o problema. As dependências que são acionadas são as do objeto, o que significa que se o objeto possuir uma propriedade para cada chave, todas as dependências de todas as chaves são acionadas ao apenas adicionar uma chave.

Portanto, usar objetos simples para simular um mapa não parece a solução certa e, portanto, ter suporte para um mapa em vue é mais do que bem-vindo para grandes coleções de itens.

Há alguma notícia sobre planos futuros e possivelmente sobre o suporte nativo Map/Set ?

Este artigo detalha o futuro suporte no 2.6 - mas não há nada sobre isso no roteiro oficial pelo que posso ver?

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

"O mais recente do núcleo é 2.5.x. Próxima versão secundária (v2.6), oferecerá suporte à importação de ESM nativa, tratamento de erros assíncronos aprimorado, iterador na diretiva 'v-for' e muito mais."

Não tem certeza de onde eles conseguiram essa informação?

Encontrou este problema enquanto estava depurando o comportamento do Vue em Set objetos de dados. :pensando:

Para pessoas como eu que estavam se perguntando sobre o roteiro para isso, Evan You diz neste vídeo que o suporte para Map and Set "provavelmente" chegará no 2.6, mas isso foi em maio, então é tudo que eu sei.

@ yyx990803 É uma pena que esse problema no rastreador esteja marcado como encerrado, especialmente se você estiver pensando em adicionar suporte em um futuro próximo. Onde podemos acompanhar o progresso desse recurso? Existe outro problema em algum lugar?

Só estou pensando, e talvez eu esteja fazendo errado, mas como você pode rastrear a mutação de um array usando os Métodos de Mutação, você não pode simplesmente rastrear um array de um objeto e ser logicamente completo? você não tem todos os mesmos recursos implementados no Map, mas aqueles que você deseja seriam facilmente resolvidos, especialmente se você estiver usando algo como _ ou lodash.

É triste, mas até que a equipe adicione isso, talvez tenhamos que usar estruturas de dados alternativas

Quero apenas alertar que iríamos usar um mapa para nossa estrutura de dados, mas decidimos não fazê-lo devido à falta de apoio de primeira parte.

agora é compatível com Vue3 (ou seja, Map reativo e Set )?

Esta página foi útil?
0 / 5 - 0 avaliações