Reatividade sob demanda no Vue 3

Publicados: 2022-03-11

Além de melhorias de desempenho admiráveis, o recém-lançado Vue 3 também trouxe várias novidades. Indiscutivelmente a introdução mais importante é a API de composição . Na primeira parte deste artigo, recapitulamos a motivação padrão para uma nova API: melhor organização e reutilização do código. Na segunda parte, focaremos em aspectos menos discutidos do uso da nova API, como a implementação de recursos baseados em reatividade que eram inexprimíveis no sistema de reatividade do Vue 2.

Vamos nos referir a isso como reatividade sob demanda . Depois de apresentar os novos recursos relevantes, construiremos um aplicativo de planilha simples para demonstrar a nova expressividade do sistema de reatividade do Vue. No final, discutiremos que uso no mundo real essa reatividade sob demanda pode ter.

O que há de novo no Vue 3 e por que é importante

O Vue 3 é uma grande reescrita do Vue 2, introduzindo uma infinidade de melhorias, mantendo a compatibilidade com versões anteriores com a API antiga quase em sua totalidade.

Um dos novos recursos mais significativos do Vue 3 é a API de composição . Sua introdução provocou muita controvérsia quando foi discutida pela primeira vez publicamente. Caso você ainda não esteja familiarizado com a nova API, primeiro descreveremos a motivação por trás dela.

A unidade usual de organização de código é um objeto JavaScript cujas chaves representam vários tipos possíveis de uma parte de um componente. Assim, o objeto pode ter uma seção para dados reativos ( data ), outra seção para propriedades computadas ( computed ), mais uma seção para métodos de componentes ( methods ), etc.

Sob este paradigma, um componente pode ter várias funcionalidades não relacionadas ou relacionadas livremente, cujos funcionamentos internos são distribuídos entre as seções de componentes mencionadas. Por exemplo, podemos ter um componente para upload de arquivos que implementa duas funcionalidades essencialmente separadas: gerenciamento de arquivos e um sistema que controla a animação do status do upload.

A parte <script> pode conter algo como o seguinte:

 export default { data () { return { animation_state: 'playing', animation_duration: 10, upload_filenames: [], upload_params: { target_directory: 'media', visibility: 'private', } } }, computed: { long_animation () { return this.animation_duration > 5; }, upload_requested () { return this.upload_filenames.length > 0; }, }, ... }

Há benefícios nessa abordagem tradicional de organização de código, principalmente no fato de o desenvolvedor não precisar se preocupar com onde escrever um novo trecho de código. Se estivermos adicionando uma variável reativa, nós a inserimos na seção de data . Se estivermos procurando por uma variável existente, sabemos que ela deve estar na seção de data .

Essa abordagem tradicional de dividir a implementação da funcionalidade em seções ( data , computed , etc.) não é adequada em todas as situações.

As seguintes exceções são frequentemente citadas:

  1. Lidar com um componente com um grande número de funcionalidades. Se quisermos atualizar nosso código de animação com a capacidade de atrasar o início da animação, por exemplo, teremos que rolar/pular entre todas as seções relevantes do componente em um editor de código. No caso do nosso componente de upload de arquivos, o componente em si é pequeno e o número de funcionalidades que ele implementa também é pequeno. Assim, neste caso, pular entre as seções não é realmente um problema. Essa questão de fragmentação de código torna-se relevante quando lidamos com componentes grandes.
  2. Outra situação em que falta a abordagem tradicional é a reutilização de código. Frequentemente precisamos fazer uma combinação específica de dados reativos, propriedades computadas, métodos, etc., disponíveis em mais de um componente.

O Vue 2 (e o Vue 3 compatível com versões anteriores) oferece uma solução para a maioria dos problemas de organização e reutilização de código: mixins .

Prós e contras de Mixins no Vue 3

Mixins permitem que as funcionalidades de um componente sejam extraídas em uma unidade de código separada. Cada funcionalidade é colocada em um mixin separado e cada componente pode usar um ou mais mixins. Peças definidas em um mixin podem ser usadas em um componente como se fossem definidas no próprio componente. Os mixins são um pouco como classes em linguagens orientadas a objetos, pois coletam o código relacionado a uma determinada funcionalidade. Assim como as classes, os mixins podem ser herdados (usados) em outras unidades de código.

No entanto, o raciocínio com mixins é mais difícil, pois, diferentemente das classes, os mixins não precisam ser projetados com encapsulamento em mente. Mixins podem ser coleções de pedaços de código frouxamente ligados sem uma interface bem definida para o mundo exterior. Usar mais de um mixin por vez no mesmo componente pode resultar em um componente difícil de compreender e usar.

A maioria das linguagens orientadas a objetos (por exemplo, C# e Java) desencoraja ou até mesmo proíbe a herança múltipla, apesar de o paradigma de programação orientada a objetos ter as ferramentas para lidar com tal complexidade. (Algumas linguagens permitem herança múltipla, como C++, mas a composição ainda é preferível à herança.)

Um problema mais prático que pode ocorrer ao usar mixins no Vue é a colisão de nomes, que ocorre ao usar dois ou mais mixins declarando nomes comuns. Deve-se notar aqui que se a estratégia padrão do Vue para lidar com colisões de nomes não for ideal em uma determinada situação, a estratégia pode ser ajustada pelo desenvolvedor. Isso tem o custo de introduzir mais complexidade.

Outra questão é que os mixins não oferecem algo parecido com um construtor de classe. Isso é um problema porque muitas vezes precisamos que funcionalidades muito semelhantes, mas não exatamente iguais, estejam presentes em componentes diferentes. Isso pode ser contornado em alguns casos simples com o uso de fábricas de mixin.

Portanto, mixins não são a solução ideal para organização e reutilização de código, e quanto maior o projeto, mais sérios se tornam seus problemas. O Vue 3 apresenta uma nova maneira de resolver os mesmos problemas relacionados à organização e reutilização de código.

API de composição: resposta do Vue 3 à organização e reutilização do código

A API de composição nos permite (mas não nos exige) desacoplar completamente as partes de um componente. Cada pedaço de código — uma variável, uma propriedade computada, um relógio, etc. — pode ser definido independentemente.

Por exemplo, em vez de ter um objeto que contém uma seção de data que contém uma chave animation_state com o valor (padrão) “playing”, agora podemos escrever (em qualquer lugar em nosso código JavaScript):

 const animation_state = ref('playing');

O efeito é quase o mesmo que declarar esta variável na seção de data de algum componente. A única diferença essencial é que precisamos tornar o ref definido fora do componente disponível no componente onde pretendemos usá-lo. Fazemos isso importando seu módulo para o local onde o componente está definido e retornamos a ref da seção de setup de um componente. Vamos pular este procedimento por enquanto e focar apenas na nova API por um momento. A reatividade no Vue 3 não requer um componente; na verdade é um sistema autônomo.

Podemos usar a variável animation_state em qualquer escopo para o qual importamos essa variável. Depois de construir um ref , obtemos e definimos seu valor real usando ref.value , por exemplo:

 animation_state.value = 'paused'; console.log(animation_state.value);

Precisamos do sufixo '.value' já que o operador de atribuição, de outra forma, atribuiria o valor (não reativo) “pausado” à variável animation_state . A reatividade em JavaScript (tanto quando é implementada através do defineProperty como no Vue 2, quanto quando é baseada em um Proxy como no Vue 3) requer um objeto cujas chaves possamos trabalhar de forma reativa.

Observe que esse foi o caso do Vue 2 também; lá, tínhamos um componente como prefixo para qualquer membro de dados reativo ( component.data_member ). A menos e até que o padrão da linguagem JavaScript introduza a capacidade de sobrecarregar o operador de atribuição, as expressões reativas exigirão que um objeto e uma chave (por exemplo, animation_state e value como acima) apareçam no lado esquerdo de qualquer operação de atribuição em que desejamos preservar a reatividade.

Nos templates, podemos omitir .value já que o Vue precisa pré-processar o código do template e pode detectar automaticamente as referências:

 <animation :state='animation_state' />

Em teoria, o compilador Vue também poderia pré-processar a parte <script> de um Single File Component (SFC) de maneira semelhante, inserindo .value onde necessário. No entanto, o uso de refs seria diferente com base no fato de estarmos usando SFCs ou não, portanto, talvez esse recurso nem seja desejável.

Às vezes, temos uma entidade (por exemplo, um objeto Javascript ou um array) que nunca pretendemos substituir por uma instância completamente diferente. Em vez disso, podemos estar interessados ​​apenas em modificar seus campos de chave. Há uma abreviação neste caso: usar reactive em vez de ref nos permite dispensar o .value :

 const upload_params = reactive({ target_directory: 'media', visibility: 'private', }); upload_params.visibility = 'public'; // no `.value` needed here // if we did not make `upload_params` constant, the following code would compile but we would lose reactivity after the assignment; it is thus a good idea to make reactive variables ```const``` explicitly: upload_params = { target_directory: 'static', visibility: 'public', };

A reatividade desacoplada com ref e reactive não é um recurso completamente novo do Vue 3. Foi parcialmente introduzido no Vue 2.6, onde tais instâncias desacopladas de dados reativos eram chamadas de “observáveis”. Na maioria das vezes, pode-se substituir Vue.observable por reactive . Uma das diferenças é que acessar e alterar o objeto passado para o Vue.observable diretamente é reativo, enquanto a nova API retorna um objeto proxy, portanto, a mutação do objeto original não terá efeitos reativos.

Comparação: API de opções vs. API de composição.

O que é completamente novo no Vue 3 é que outras partes reativas de um componente agora também podem ser definidas independentemente, além de dados reativos. Propriedades computadas são implementadas de uma maneira esperada:

 const x = ref(5); const x_squared = computed(() => x.value * x.value); console.log(x_squared.value); // outputs 25

Da mesma forma, pode-se implementar vários tipos de relógios, métodos de ciclo de vida e injeção de dependência. Por uma questão de brevidade, não vamos cobri-los aqui.

Suponha que usamos a abordagem SFC padrão para o desenvolvimento do Vue. Podemos até estar usando a API tradicional, com seções separadas para dados, propriedades computadas, etc. Como integramos os pequenos bits de reatividade da API de composição com SFCs? O Vue 3 apresenta outra seção apenas para isso: setup . A nova seção pode ser pensada como um novo método de ciclo de vida (que é executado antes de qualquer outro gancho—em particular, antes de created ).

Aqui está um exemplo de um componente completo que integra a abordagem tradicional com a API de composição:

 <template> <input v-model="x" /> <div>Squared: {{ x_squared }}, negative: {{ x_negative }}</div> </template> <script> import { ref, computed } from 'vue'; export default { name: "Demo", computed: { x_negative() { return -this.x; } }, setup() { const x = ref(0); const x_squared = computed(() => x.value * x.value); return {x, x_squared}; } } </script>

Coisas para tirar deste exemplo:

  • Todo o código da API de composição está agora em setup . Você pode querer criar um arquivo separado para cada funcionalidade, importar esse arquivo em um SFC e retornar os bits de reatividade desejados da setup (para disponibilizá-los para o restante do componente).
  • Você pode misturar a abordagem nova e tradicional no mesmo arquivo. Observe que x , mesmo sendo uma referência, não requer .value quando referido no código do modelo ou em seções tradicionais de um componente como computed .
  • Por último, mas não menos importante, observe que temos dois nós raiz DOM em nosso modelo; a capacidade de ter vários nós raiz é outro novo recurso do Vue 3.

A reatividade é mais expressiva no Vue 3

Na primeira parte deste artigo, abordamos a motivação padrão para a API de composição, que é a organização e a reutilização de código aprimoradas. De fato, o principal ponto de venda da nova API não é seu poder, mas a conveniência organizacional que ela traz: a capacidade de estruturar o código com mais clareza. Pode parecer que isso é tudo - que a API de composição permite uma maneira de implementar componentes que evita as limitações das soluções já existentes, como mixins.

No entanto, há mais na nova API. A API de composição permite não apenas sistemas reativos mais organizados, mas mais poderosos. O ingrediente chave é a capacidade de adicionar reatividade dinamicamente ao aplicativo. Anteriormente, era necessário definir todos os dados, todas as propriedades computadas, etc. antes de carregar um componente. Por que adicionar objetos reativos em um estágio posterior seria útil? No que resta, damos uma olhada em um exemplo mais complexo: planilhas.

Criando uma planilha no Vue 2

Ferramentas de planilhas como Microsoft Excel, LibreOffice Calc e Google Sheets têm algum tipo de sistema de reatividade. Essas ferramentas apresentam ao usuário uma tabela, com colunas indexadas por A–Z, AA–ZZ, AAA–ZZZ, etc., e linhas indexadas numericamente.

Cada célula pode conter um valor simples ou uma fórmula. Uma célula com uma fórmula é essencialmente uma propriedade computada, que pode depender de valores ou outras propriedades computadas. Com planilhas padrão (e ao contrário do sistema de reatividade em Vue), essas propriedades computadas podem até depender de si mesmas! Tal autorreferência é útil em alguns cenários onde o valor desejado é obtido por aproximação iterativa.

Assim que o conteúdo de uma célula for alterado, todas as células que dependem da célula em questão acionarão uma atualização. Se ocorrerem outras alterações, mais atualizações podem ser agendadas.

Se fôssemos construir um aplicativo de planilha com Vue, seria natural perguntar se podemos usar o próprio sistema de reatividade do Vue e fazer do Vue o mecanismo de um aplicativo de planilha. Para cada célula, podemos lembrar seu valor bruto editável, bem como o valor calculado correspondente. Os valores calculados refletiriam o valor bruto se for um valor simples e, caso contrário, os valores calculados são o resultado da expressão (fórmula) que é escrita em vez de um valor simples.

Com o Vue 2, uma maneira de implementar uma planilha é ter raw_values ​​um array bidimensional de strings e computed_values ​​um array bidimensional (computado) de valores de células.

Se o número de células for pequeno e fixo antes do carregamento do componente Vue apropriado, poderíamos ter um valor bruto e um valor calculado para cada célula da tabela em nossa definição de componente. Além da monstruosidade estética que tal implementação causaria, uma tabela com um número fixo de células em tempo de compilação provavelmente não conta como uma planilha.

Há problemas com o array bidimensional computed_values ​​, também. Uma propriedade computada é sempre uma função cuja avaliação, neste caso, depende de si mesma (o cálculo do valor de uma célula exigirá, em geral, que alguns outros valores já estejam computados). Mesmo que o Vue permitisse propriedades computadas auto-referenciais, atualizar uma única célula faria com que todas as células fossem recalculadas (independentemente de haver dependências ou não). Isso seria extremamente ineficiente. Assim, podemos acabar usando reatividade para detectar mudanças nos dados brutos com o Vue 2, mas todo o resto em reatividade teria que ser implementado do zero.

Modelando Valores Computados no Vue 3

Com o Vue 3, podemos introduzir uma nova propriedade computada para cada célula. Se a tabela cresce, novas propriedades computadas são introduzidas.

Suponha que temos as células A1 e A2 e desejamos que A2 exiba o quadrado de A1 cujo valor é o número 5. Um esboço desta situação:

 let A1 = computed(() => 5); let A2 = computed(() => A1.value * A1.value); console.log(A2.value); // outputs 25

Suponha que permaneçamos neste cenário simples por um momento. Há um problema aqui; e se quisermos alterar A1 para que contenha o número 6? Suponha que escrevemos isso:

 A1 = computed(() => 6); console.log(A2.value); // outputs 25 if we already ran the code above

Isso não apenas alterou o valor de 5 para 6 em A1 . A variável A1 tem uma identidade completamente diferente agora: a propriedade computada que resolve para o número 6. No entanto, a variável A2 ainda reage a mudanças da identidade antiga da variável A1 . Assim, A2 não deve se referir diretamente a A1 , mas sim a algum objeto especial que sempre estará disponível no contexto, e nos dirá o que é A1 no momento. Em outras palavras, precisamos de um nível de indireção antes de acessar A1 , algo como um ponteiro. Não há ponteiros como entidades de primeira classe em Javascript, mas é fácil simular um. Se quisermos ter um pointer apontando para um value , podemos criar um pointer = {points_to: value} . Redirecionar o ponteiro equivale a atribuir a pointer.points_to , e desreferenciar (acessar o valor apontado) equivale a recuperar o valor de pointer.points_to . No nosso caso procedemos da seguinte forma:

 let A1 = reactive({points_to: computed(() => 5)}); let A2 = reactive({points_to: computed(() => A1.points_to * A1.points_to)}); console.log(A2.points_to); // outputs 25

Agora podemos substituir 5 por 6.

 A1.points_to = computed(() => 6); console.log(A2.points_to); // outputs 36

No servidor Discord do Vue, o usuário redblobgames sugeriu outra abordagem interessante: em vez de usar valores computados, use referências que envolvam funções regulares. Dessa forma, pode-se trocar a função de maneira semelhante sem alterar a identidade da própria referência.

Nossa implementação de planilha terá células referenciadas por chaves de algum array bidimensional. Essa matriz pode fornecer o nível de indireção que precisamos. Assim, em nosso caso, não precisaremos de nenhuma simulação de ponteiro adicional. Poderíamos até ter um array que não distinguisse entre valores brutos e calculados. Tudo pode ser um valor calculado:

 const cells = reactive([ computed(() => 5), computed(() => cells[0].value * cells[0].value) ]); cells[0] = computed(() => 6); console.log(cells[1].value); // outputs 36

No entanto, realmente queremos distinguir valores brutos e calculados, pois queremos poder vincular o valor bruto a um elemento de entrada HTML. Além disso, se tivermos uma matriz separada para valores brutos, nunca teremos que alterar as definições das propriedades computadas; eles serão atualizados automaticamente com base nos dados brutos.

Implementando a planilha

Vamos começar com algumas definições básicas, que na maioria das vezes são autoexplicativas.

 const rows = ref(30), cols = ref(26); /* if a string codes a number, return the number, else return a string */ const as_number = raw_cell => /^[0-9]+(\.[0-9]+)?$/.test(raw_cell) ? Number.parseFloat(raw_cell) : raw_cell; const make_table = (val = '', _rows = rows.value, _cols = cols.value) => Array(_rows).fill(null).map(() => Array(_cols).fill(val)); const raw_values = reactive(make_table('', rows.value, cols.value)); const computed_values = reactive(make_table(undefined, rows.value, cols.value)); /* a useful metric for debugging: how many times did cell (re)computations occur? */ const calculations = ref(0);

O plano é para que cada computed_values[row][column] seja calculado da seguinte forma. Se raw_values[row][column] não começar com = , retorne raw_values[row][column] . Caso contrário, analise a fórmula, compile-a para JavaScript, avalie o código compilado e retorne o valor. Para manter as coisas curtas, vamos trapacear um pouco com fórmulas de análise e não faremos algumas otimizações óbvias aqui, como um cache de compilação.

Assumiremos que os usuários podem inserir qualquer expressão JavaScript válida como uma fórmula. Podemos substituir as referências aos nomes das células que aparecem nas expressões do usuário, como A1, B5, etc., pela referência ao valor real da célula (computado). A função a seguir faz esse trabalho, assumindo que strings que se assemelham a nomes de células sempre identificam células (e não fazem parte de alguma expressão JavaScript não relacionada). Para simplificar, vamos supor que os índices de coluna consistem em uma única letra.

 const letters = Array(26).fill(0) .map((_, i) => String.fromCharCode("A".charCodeAt(0) + i)); const transpile = str => { let cell_replacer = (match, prepend, col, row) => { col = letters.indexOf(col); row = Number.parseInt(row) - 1; return prepend + ` computed_values[${row}][${col}].value `; }; return str.replace(/(^|[^AZ])([AZ])([0-9]+)/g, cell_replacer); };

Usando a função transpile , podemos obter expressões JavaScript puras de expressões escritas em nossa pequena “extensão” de JavaScript com referências de células.

O próximo passo é gerar propriedades computadas para cada célula. Este procedimento ocorrerá uma vez no tempo de vida de cada célula. Podemos fazer uma fábrica que retornará as propriedades computadas desejadas:

 const computed_cell_generator = (i, j) => { const computed_cell = computed(() => { // we don't want Vue to think that the value of a computed_cell depends on the value of `calculations` nextTick(() => ++calculations.value); let raw_cell = raw_values[i][j].trim(); if (!raw_cell || raw_cell[0] != '=') return as_number(raw_cell); let user_code = raw_cell.substring(1); let code = transpile(user_code); try { // the constructor of a Function receives the body of a function as a string let fn = new Function(['computed_values'], `return ${code};`); return fn(computed_values); } catch (e) { return "ERROR"; } }); return computed_cell; }; for (let i = 0; i < rows.value; ++i) for (let j = 0; j < cols.value; ++j) computed_values[i][j] = computed_cell_generator(i, j);

Se colocarmos todo o código acima no método de setup , precisamos retornar {raw_values, computed_values, rows, cols, letters, calculations} .

Abaixo, apresentamos o componente completo, juntamente com uma interface de usuário básica.

O código está disponível no GitHub e você também pode conferir a demonstração ao vivo.

 <template> <div> <div>Calculations: {{ calculations }}</div> <table class="table" border="0"> <tr class="row"> <td></td> <td class="column" v-for="(_, j) in cols" :key="'header' + j" > {{ letters[j] }} </td> </tr> <tr class="row" v-for="(_, i) in rows" :key="i" > <td class="column"> {{ i + 1 }} </td> <td class="column" v-for="(__, j) in cols" :key="i + '-' + j" :class="{ column_selected: active(i, j), column_inactive: !active(i, j), }" @click="activate(i, j)" > <div v-if="active(i, j)"> <input :ref="'input' + i + '-' + j" v-model="raw_values[i][j]" @keydown.enter.prevent="ui_enter()" @keydown.esc="ui_esc()" /> </div> <div v-else v-html="computed_value_formatter(computed_values[i][j].value)"/> </td> </tr> </table> </div> </template> <script> import {ref, reactive, computed, watchEffect, toRefs, nextTick, onUpdated} from "vue"; export default { name: 'App', components: {}, data() { return { ui_editing_i: null, ui_editing_j: null, } }, methods: { get_dom_input(i, j) { return this.$refs['input' + i + '-' + j]; }, activate(i, j) { this.ui_editing_i = i; this.ui_editing_j = j; nextTick(() => this.get_dom_input(i, j).focus()); }, active(i, j) { return this.ui_editing_i === i && this.ui_editing_j === j; }, unselect() { this.ui_editing_i = null; this.ui_editing_j = null; }, computed_value_formatter(str) { if (str === undefined || str === null) return 'none'; return str; }, ui_enter() { if (this.ui_editing_i < this.rows - 1) this.activate(this.ui_editing_i + 1, this.ui_editing_j); else this.unselect(); }, ui_esc() { this.unselect(); }, }, setup() { /*** All the code we wrote above goes here. ***/ return {raw_values, computed_values, rows, cols, letters, calculations}; }, } </script> <style> .table { margin-left: auto; margin-right: auto; margin-top: 1ex; border-collapse: collapse; } .column { box-sizing: border-box; border: 1px lightgray solid; } .column:first-child { background: #f6f6f6; min-width: 3em; } .column:not(:first-child) { min-width: 4em; } .row:first-child { background: #f6f6f6; } #empty_first_cell { background: white; } .column_selected { border: 2px cornflowerblue solid !important; padding: 0px; } .column_selected input, .column_selected input:active, .column_selected input:focus { outline: none; border: none; } </style>

E quanto ao uso no mundo real?

Vimos como o sistema de reatividade desacoplada do Vue 3 permite não apenas um código mais limpo, mas também sistemas reativos mais complexos baseados no novo mecanismo de reatividade do Vue. Aproximadamente sete anos se passaram desde que o Vue foi introduzido, e o aumento da expressividade claramente não foi muito procurado.

O exemplo da planilha é uma demonstração direta do que o Vue é capaz agora, e você também pode conferir a demonstração ao vivo.

Mas como um exemplo de palavra real, é um pouco de nicho. Em que tipo de situações o novo sistema pode ser útil? O caso de uso mais óbvio para reatividade sob demanda pode estar em ganhos de desempenho para aplicativos complexos.

Comparação de funil Vue 2 vs Vue 3.

Em aplicativos front-end que trabalham com uma grande quantidade de dados, a sobrecarga de usar reatividade mal pensada pode ter um impacto negativo no desempenho. Suponha que tenhamos um aplicativo de painel de negócios que produz relatórios interativos da atividade comercial da empresa. O usuário pode selecionar um intervalo de tempo e adicionar ou remover indicadores de desempenho no relatório. Alguns indicadores podem exibir valores que dependem de outros indicadores.

Uma forma de implementar a geração de relatórios é através de uma estrutura monolítica. Quando o usuário altera um parâmetro de entrada na interface, uma única propriedade computada, por exemplo, report_data , é atualizada. O cálculo dessa propriedade computada acontece de acordo com um plano codificado: primeiro, calcule todos os indicadores de desempenho independentes, depois aqueles que dependem apenas desses indicadores independentes, etc.

Uma implementação melhor irá desacoplar bits do relatório e computá-los independentemente. Existem alguns benefícios para isso:

  • O desenvolvedor não precisa codificar um plano de execução, que é tedioso e propenso a erros. O sistema de reatividade do Vue detectará automaticamente as dependências.
  • Dependendo da quantidade de dados envolvidos, podemos obter ganhos substanciais de desempenho, pois estamos atualizando apenas os dados do relatório que dependiam logicamente dos parâmetros de entrada modificados.

Se todos os indicadores de desempenho que podem fazer parte do relatório final forem conhecidos antes que o componente Vue seja carregado, poderemos implementar o desacoplamento proposto mesmo com o Vue 2. Caso contrário, se o backend for a única fonte de verdade (que é geralmente é o caso de aplicativos orientados a dados), ou se houver provedores de dados externos, podemos gerar propriedades computadas sob demanda para cada parte de um relatório.

Graças ao Vue 3, isso agora não é apenas possível, mas fácil de fazer.