Vue.js: Componentes Dinâmicos

Vue.js: Componentes Dinâmicos

Disclaimer: Esse artigo é sobre a história de um desenvolvedor que está sempre em busca de automatizar o que faz e narra como o Vue pode ser uma boa opção para criação de interfaces dinâmicas. Já pensou em ter apenas um componente de formulário no seu projeto?! Apenas um grid?! Se a ideia te agrada esse artigo vai fazer sentido; do contrário pode servir para abrir a sua mente.

O Problema

Inicialmente vamos fazer um nivelamento sobre alguns conceitos tradicionais na programação. Para esse tópico, criei este formulário de demonstração com uma ferramenta muito comum para escrita de interface (bootstrap) com apenas um campo.

Veja que temos ali uma div #app sobre a qual é montada uma instância do Vue e dentro dela algumas tags como<form>, <input> e etc. Creio que seja um consenso que esse template esteja bem simples de ser mantido, porém vou convidar você, leitor, para pensar um pouco além do que está no nosso campo de visão.

Quando olhamos mais atentamente para esse <form> vemos marcações no HTML e uma certa estrutura a ser seguida (aka markup) que são familiares ao contexto que estamos adotando. Além disso, embora este primeiro exemplo esteja bem simples, não é nada incomum ver formulários bem mais extensos e com muito mais informação estática, mapeamento de eventos, mensagens de validações e tantas outras necessidades que o desenvolvimento pode propiciar.

Para crescer a aplicação é comum o desenvolvedor copiar e colar alguns trechos de código, mudar algumas coisinhas e seguir para o próximo campo. Ao final desse processo, na prática, o que vamos ter é uma quantidade bem grande de código (vamos combinar que tudo que for escrito para fazer o software rodar é código) em uma quantidade bem grande de arquivos que são totalmente dependentes da ferramenta visual adotada e que fazem com que trocar algumas coisas no projeto seja quase que refazer ele.

Entendendo o Contexto

Voltando ao meu primeiro exemplo que vimos no artigo, vamos procurar naquela marcação HTML o que são estados da minha aplicação e o que é parte do esqueleto que o Bootstrap entrega.

Note que na imagem temos algumas marcações delineando itens que merecem nossa atenção. Os retângulos vermelhos representam os elementos que fazem parte do universo do Bootstrap, já as elipses verdes representam recursos envolvidos com a lógica impressa pela aplicação.

Esses dois grandes grupos são importantes e veremos mais sobre cada um deles a seguir. Por enquanto fique com essa ideia e tente exercitá-la olhando seus códigos e pensando em como poderia aplicar essa divisão por lá.

Interface Descartável e Flexível

Não é mais segredo para ninguém em pleno 2018: aparência importa. Sendo assim se sua aplicação não for pensada para ter a capacidade de se adaptar rapidamente à mudanças visuais estará comprometendo um grande esforço para ficar refazendo telas porque seu framework não é mais mantido ou porque a nova versão dele devastou tudo o que tinha sido escrito.

Para evitar isso podemos usar componentes customizados. Ao invés de declararmos explicitamente um <input> e todo o markup que o rodeia vamos criar um componente que encapsule-o.

Com essa mudança passa a ser irrelevante qual o markup HTML que será executado. Poderíamos ter 500 <input> nesse <form>que para atualizar TODOS eles precisaríamos mudar apenas um local. Obviamente que esse mesmo conceito aplicaria-se a toda uma aplicação.

Procure não usar diretamente recursos de nenhuma biblioteca ou framework. Centralize a relação entre seu código e o código alheio em pontos chave.

Note que em momento nenhum eu disse que seria algo fácil e nem que conseguiremos fazer isso sempre. A dica é tentar fazer o máximo que puder para evitar refatorações sucessivas e constantes.

Controle de Estados

O termo estado está se tornando cada vez mais popular (assim como algoritmo), o que demonstra que o desenvolvimento de software tem amadurecido à passos largos. Quando usamos este termo na nossa aplicação estamos geralmente fazendo referência aos dados que estão sendo manipulados e persistidos. Contudo há mais para se ver sobre isso.

[https://jsfiddle.net/wilcorrea/hwuog723](https://cdn.hashnode.com/res/hashnode/image/upload/v1617062655171/d9X4vQaW_.html)https://jsfiddle.net/wilcorrea/hwuog723

Com estas modificações nosso exemplo agora consegue gerenciar o valor do campo de descrição usando um componente que mapeia o estado que será usado como estrada e saída do sistema; todavia ele ainda possui estados para administrar o <label>que será exibido, formatando e modificando o componente renderizado.

Não vou me aprofundar muito sobre os comandos usados (se tiver dúvidas sobre algo pode consultar a doc, expressar-se por meio dos comentários, ou entrar em contato de alguma forma) porque não é o foco do artigo; estamos falando de abstração e demonstrando possíveis abordagens apenas para validar a ideia.

Os estados da sua aplicação são responsáveis por prover subsídios para a resolução dos problemas que ela pretende resolver. Trate-os como prioridade.

Estados Circunstanciais

Creio que todos os leitores que estiverem lendo esse trecho agora já interagiram com telas que reagem de alguma forma aos valores informados reconfigurando o que está visível de forma a guiar o fluxo e/ou garantir uma entrada mais adequada de dados. É possível ver estados mapeados na interface para exibir/ocultar ou alterá-la circunstancialmente e eventos que alteram esses mesmos estados.

Vamos considerar nesse ponto que há dois tipos de estados na sua aplicação: um grupo de estados que representa a entrada e saída de dados da sua aplicação e um outro grupo que é responsável por configurar os componentes da tela. Estas duas dimensões de estados são relevantes para o sistema. A “lógica” que os estados dos componentes possui é muito primitiva; ela está basicamente relacionada a laços e testes lógicos para determinar quais propriedades devem ser exibidas em um dado contexto, mas ainda assim ela é importante.

O seu template é descartável, mas a lógica por trás dos seus componentes não é!

Na verdade a lógica por trás dos componentes é, provavelmente, tão importante quanto o I/O (Input/Output) que sua aplicação provê. Algumas partes de alguns programas podem ser totalmente prejudicadas caso os estados que manipulam os componentes de tela sejam comprometidos. Interfaces para cadastros de pessoas física e jurídica, por exemplo, exibem um indicador de qual tipo de pessoa será persistido e também redefinem os campos na tela. Pode ser, inclusive, que a alteração do valor contido o campo que define o tipo de pessoa, além de mudar os campos de tela, redefina o destino que será usado para a persistência da informação coletada, tornando ainda mais crítico o papel desses estados.

Composição de Componentes

Basicamente um componente (WebComponents também) vai ser um conjunto de recursos que pode ser usado e re-usado em diversos locais. Como estamos usando VueJS para os exemplos, segue um exemplo de um componente que pode ser reusado como um módulo Javascript.

Este componente poderia ter qualquer nome, mas com base no que temos na imagem acima vamos considerar que ele será registrado globalmente ou para o escopo local como FieldInput, o que resultaria na disponibilidade da tag <field-input> para os templates (isto pode ser visto nos exemplos acima). A necessidade de escrever essa tag toda vez que eu precisar desse componente me impede que eu possa criar um form sem escrever pelo menos essa marcação e reduz as minhas chances de fazer telas ainda mais dinâmicas.

Sabendo disso o Vue disponibiliza em sua renderização de templates um recurso chamado de Dynamic Component e vamos ver como fazer uso dela no exemplo abaixo.

[https://cdn.hashnode.com/res/hashnode/image/upload/v1617062658541/aJwHvdiM3.html](https://jsfiddle.net/wilcorrea/nq0b7qwo/39/)https://jsfiddle.net/wilcorrea/nq0b7qwo/39/

Na linha 4 da seção HTML é possível ver a tag <component> e sua prop is. Essa propriedade permite-nos declarar um component sobre a tag <component>. Sendo assim o valor que eu passar para a prop is deverá ser o identificador de um componente e o mesmo será instanciado na resolução do template. Esta prática retira de nós a responsabilidade de criar cada <tag> de cada campo de nossas telas. Ao invés de declarar cada item podemos usar uma diretiva para percorrer os metadados de um elemento que foi declarado em Javascript, para que estes sejam os responsáveis por prover os dados necessários para criar a interface.

Obviamente que isto seria apenas o começo e te abre inúmeras portas para inúmeras construções. Podemos manter seus modelos em domínios e criar as rotas de forma a consumir esses recursos. Um componente poderia ser também qualquer coisa; além de campos de formulários, poderíamos ter menus, sliders, banners e qualquer coisa que fizesse algum sentido ser organizado dessa forma dentro do seu projeto.

Nem tudo são flores!

No último tópico deste artigo demonstramos como usar componentes dinâmicos, como bom desenvolvedor, você já deve ter sacado a quantidade de possibilidades que a utilização de metadados para suportar uma camada de abstração sobre os seus componentes e seu I/O pode ser vantajosa. O que eu preciso te contar agora são das dificuldades que isso vai te trazer:

  • Mensagens de erro pouco amigáveis: se até então tínhamos mensagens bem claras sobre os erros quando construímos um workflow explícito, usando abordagens dinâmicas isso não será mais realidade. Será preciso ter cuidado com erros e construir passo-a-passo suas composições para não se perder;

  • Alto nível de acoplamento: componentes dinâmicos vão aumentar exponencialmente o acoplamento do seu projeto. O bater de asas de uma borboleta em um componente vai se refletir em todo o projeto. Crie testes e organize como serão feitas mudanças nesses componentes centrais;

  • Conhecimento avançado da linguagem: quando usamos composições dinâmicas ganha-se em tempo e em reuso, mas é preciso ter conhecimentos avançados sobre a linguagem que está manipulando. No caso do Vue usamos Javascript, e, em pouco tempo seu projeto passará a ser sobre Javascript e terá pouco a se tratar sobre Vue, que ficará isolado nas interações de tela, componentes padrões e alguns componentes customizados que não valerão o esforço de torná-los agnósticos;

  • Crie contratos: para manter um controle de crescimento sadio será preciso estipular contratos de funcionamento no workflow, e, nada mais útil do que usar recursos da própria linguagem. No caso do exemplo que eu mostrei a propriedade schema deveria ser criada por algum método, classe ou qualquer estrutura que sua linguagem ofereça para padronizar a criação de recursos;

  • Abstração como arma e crescimento horizontal: componentes dinâmicos transformam seu projeto em provedores de abstração. Nunca permita que um módulo se torne profundo demais quando for abstrair a sua participação junto ao projeto, cresça sempre pros lados e nunca para cima ou para baixo;

  • Trabalhe pensando em exceções: criar estruturas dinâmicas requer um cuidado muito grande para que não sejam criadas fundações inflexíveis. No caso do Vue eu posso registrar componentes a qualquer momento, inclusive em tempo de execução, o que facilita atender exceções.

Talvez hajam outros desafios que não me recordo agora, se puderem contribuir com comentários e dicas será bem vindo : )

Conclusão

O objetivo deste artigo era , basicamente, mostrar como trabalhar com estruturas dinâmicas usando VueJS (ou mesmo um pouco além dele) e as vantagens e desvantagens dessa abordagem. Dentre as principais vantagens está a produtividade e o poder de manutenção centralizado, já entre as principais desvantagens estão a complexidade e acoplamento que podem fazer com que manutenções precisem ser bem pensadas e organizadas.

Se gostou do tema ou tem algo a acrescentar, por favor, entre em contato. MDD (Metadata Drive Development) é um tema bem pobre de fontes e fica complicado ter uma boa bibliografia para citar.

Caso tenham dúvidas e/ou sugestões é possível me achar por ai pelo username @wilcorrea. É comum me achar pelo Telegram ou Twitter. VueJS Brasil Grupo de discussão e aprendizado da ferramenta VueJS. Quasar: t.me/quasarframeworkbrasilt.me