DEV Community

Cover image for Vue Primeiras Impressões
Alecell for Devhat

Posted on

Vue Primeiras Impressões

Tem muitos anos que tenho um amor platônico pelo VueJS, ele tinha tudo que eu sempre quis num framework, possuía em seu ecossistema coisas legais tanto do React quanto do Angular (eca), mas eu nunca tinha pegado pra estudar Vue de fato, tampouco trabalhei em lugares que usavam Vue, então sempre que me perguntavam o que eu achava de Vue eu dizia que era maravilhoso apesar de nunca ter usado 😅

Como parte da minha retomada recente aos estudos em TI resolvi fazer algo em Vue de fato e, somado a isso, eu sempre quis fazer um masonry grid, aí, unindo o útil ao agradável, resolvi fazer um projeto de masonry grid em Vue!


O Projeto

A ideia era ser algo simples em termos de layout e lógica no geral, nada super complexo que demoraria pra fazer, tanto que acabei levando coisa de uma semana pra terminar tudo, o importante era:

  1. Fazer um masonry grid
  2. Aprender o básico de Vue

só isso

E devo dizer que estou bem satisfeito com meu foco! 😋

Inicialmente ia fazer algo que batia na API do LOL (League of Legends) pra pegar minhas últimas partidas e listar elas em masonry, mas rapidamente vi que não sabia bem qual dado usar pra ser o dado que definiria a altura do elemento, quando percebi isso mudei pra uma listagem de contribuição em projetos Open Source do Github!

Muito simples, o usuário coloca um projeto no formato user/repo, por exemplo facebook/react e eu listo os contribuidores desse projeto. A variação na altura dos cards do grid seria de acordo com quanto mais a pessoa contribuiu no projeto, mais contribuição, maior o card!


Masonry Grid

Layout

Eu sempre quis fazer uma masonry grid desde quando em 2020 eu trabalhei numa empresa que precisou fazer um, mas acabei não podendo pegar a tarefa pra deixar ela pra um dos meus juniores ;-;

Pra quem não sabe, um masonry grid é basicamente o layout do Pinterest, um grid onde as células que o compõem não possuem um tamanho fixo, assim fica um, bom, um masonry grid 😄

Fazer o masonry grid foi até que simples, inicialmente fiz pegando como referência esse vídeo do Kevin Powell, mas acabei descobrindo que a forma que ele usa nesse vídeo, mesmo sendo um vídeo de 3 anos atrás, ainda não é bem suportada entre os navegadores, na verdade, de acordo com o Can I Use ele só é suportado pelo Safari Technology Preview (nem sei o que é isso)

Can I Use mostrando que template rows para grid layout com masonry é muito mal suportado

Decepcionante!

Felizmente eu conhecia outro método de fazer masonry grid que é usando Multi-column Layout!

Pra quem não conhece, o Multi-column Layout é um formato de layout baseado em colunas (quem diria, não é mesmo 🤣), você já viu muito disso, só talvez não conheça pelo nome, por exemplo uma página de jornal (sim, o de papel) onde cada coluna é a continuação do texto

Exemplo de folha de jornal como um exemplo pro modelo de layout Multi-column

A questão é que a gente não popula as colunas com texto, mas sim com divs!

E pra fazer isso é bem simples já que esse formato de layout não se importa com qual o conteúdo que está lá dentro, ele apenas aplica o conteúdo dentro do que ele tem de espaço disponível, no fim o código que de fato faz o masonry grid acontecer no meu projeto são essas 3 linhas

.container {
  column-count: auto;
  column-gap: var(--masonry-spacing);
  column-width: 210px;
}
Enter fullscreen mode Exit fullscreen mode

column-count diz que eu não qu

ero limitar a quantidade de colunas, vai quantas couberem.

column-gap diz o espaçamento entre uma coluna e outra, no caso eu usei uma variável pra que o espaçamento entre as colunas e o espaçamento entre os itens fosse o mesmo, pra ficar algo mais uniforme mesmo evitando que eu alterasse em um lugar e tivesse que lembrar de alterar no outro lugar também.

column-width é um valor fixo pois é justamente o tamanho que eu quero pra as colunas, como a quantidade de colunas é definida dinamicamente, isso aqui diz "coloca o tanto de colunas de 210px de largura que couber na tela."

O interessante do Multi-column Layout é que ele já organiza a distribuição dos itens automaticamente pra você, então não preciso me preocupar, coisa que pode até soar estranho porque geralmente coisas que crescem pra baixo podem dar trabalho, mas nesse caso não dá, ele só sai andando e maravilha!

Cards

Como era um masonry grid precisava ainda criar os itens do grid, esses fiz de uma forma bem simples, cada item teria um gradiente de baixo pra cima de tamanho fixo, ou seja, se o container fosse pequeno o gradiente não iria da cor X pra a cor Y, ele iria da cor X até o tamanho do container, podendo não chegar na cor Y, ou seja, teria uma referência visual de barra do quanto alguém contribuiu

Comparação dos dois cards um com muitas contribuições e outro com poucas

Coloquei além do fundo um efeitinho de hover, a foto do contribuidor, o nome e a quantidade de commits, inclusive a quantidade de commits é justamente o que define o tamanho do card!

Acabei decidindo que quem teve menos que 250 contribuições iria ficar cinza porque tinha muita gente com pouca contribuição o que acabava fazendo tudo ficar vermelho o que era ruim visualmente. Pra os que contribuíram pouco também coloquei um mínimo pra a altura pra não quebrar quando fosse bem pouquinha contribuição e foi isso, bem simples a parte dos cards.


Vue

O setup inicial do projeto em Vue foi simples pra iniciar a codar logo, fui no Quick Start do site do Vue copiei o comando pnpm create vue@latest e alegria, respondi se queria TypeScript, Vuex e coisas assim, depois tudo configurado e preparado pra codar!

Na parte de codar em Vue pra mim foi um pouco complicado, eu geralmente antes de fazer um projeto, faço diversas configurações pra deixar o ambiente do jeito que eu gosto de codar, por exemplo, eu prefiro separar os arquivos de html, css e script, também costumo criar arquivos separados pra tipagem e coisas assim, mas me desafiei a fazer as coisas da forma como a comunidade em geral prefere fazer!

Assim eu codei com tudo dentro de um arquivo .vue, interfaces e afins colocava tudo dentro da tag script também e alguns outros detalhes que comento a seguir!

Extensão do Vue para VSCode

Achei inicialmente estranho que tinha uma extensão específica para Vue, mas logo entendi que é pra interpretar os arquivos .vue que não eram entendidos pelo VSCode, inclusive nessa descobri que o ChatGPT também não reconhece o formato .vue, todos os code snippets que ele me ofereceu nas perguntas que fiz eram sem cores, tudo branco no preto.

A extensão do Vue parecia funcionar direitinho, mas teve o seguinte caso que não funcionou muito bem, a colorização das coisas ficou bugada, esse código funciona, mas considera que a const é uma função porque ele não entendeu o fechamento do template string

Erro do interpretador da extensão do Vue colorindo erroneamente o const

Fora isso não tive outros problemas, mas fico me perguntando se não existem outros problemas nessa parada além do que eu experienciei.

Sintaxe e Estrutura

A sintaxe do Vue (falando de Vue3) é bastante interessante, o modo como gerar loops e condicionais pra renderização de tags é bem semelhante a como o Angular faz

, tudo dentro das tags, o que facilita a leitura das tags em si, sem .map no meio de tags coisa que eu odeio porque pra mim isso prejudica a leitura.

O modo como o Vue funciona foi estranho pra mim de início, não é uma classe, não é uma função, ele apenas é, existe, você usa métodos pra definir interface de props e outros métodos que à primeira vista não parecem se comunicar diretamente, mas se comunicam, parece até um pouco de bruxaria!

Por exemplo, em Vue3 você não precisa exportar nem fazer nada com as variáveis que você declara e recebem valores. Declarou? Já dá pra usar no <template> do componente

<script setup>
  // declaro a propriedade
  const name = 'Alecell'
</script>

<template>
  <!-- uso a propriedade -->
  <span>{{ name }}</span>
</template>
Enter fullscreen mode Exit fullscreen mode

Isso pra mim é MUITA bruxaria, não é pouca não! 🤣

Inclusive se a variável em questão for um state, que nos scripts é usado como state.value, no template não precisamos colocar o .value

<script setup>
  // declaro a propriedade
  const name = 'Alecell'

  const clearName = function() {
    name.value = ''
  }
</script>

<template>
  <!-- uso a propriedade -->
  <span>{{ name }}</span>
  <button @click="clearName">Set name</button>
</template>
Enter fullscreen mode Exit fullscreen mode

No caso acima, perceba que pra alterar o nome no script usamos name.value, mas no template podemos usar apenas name.

Nomeando Componentes e Seus Arquivos

Aqui teve uma coisa que achei bastante chata do Vue que ele me obriga a chamar um componente Card de Card[Alguma coisa] tipo CardComponent, eu não posso chamar um componente de apenas uma palavra, não entendi o motivo disso, tampouco entendi o porquê isso não poderia ser feito nos internos do Vue evitando que tenhamos que fazer isso nós mesmos, achei estranho e não achei nenhuma resposta.

Isso pode até ser necessário, mas o motivo do porquê não é feito automaticamente, é um mistério pra mim

Vue3 API

O tanto que eu fiquei em dúvida de como fazer as coisas no Vue é sacanagem, demorou, sei que não existe certo nessas coisas, mas senhor da glória, o tanto que eu fiquei em dúvida se eu deveria usar defineProps ou defineComponent é sacanagem! Não teve nenhum jeito claro através da doc sobre isso, aliás, esse problema me mostrou outro problema, que era a diferença entre Vue Composition e Vue Options

Vue Composition API VS Vue Options API

Aparentemente o Vue3 veio ano passado e com isso trazendo a Composition API, uma API que não obriga a gente a usar aquele clássico objetão do Vue

<script>
export default {
  data() {
    return { nome: 'Alecell' }
  },
  methods: {
    return {
      changeName: function(newName) {
        this.name = newName
      }
    }
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

Mas algo mais comum de se ver quando codamos, lembra até um pouco mais o React nesse caso

<script setup>
  // ref é como o useState do React
  let name = ref('Alecell')

  const changeName = function(newName) {
    name.value = newName
  }
</script>
Enter fullscreen mode Exit fullscreen mode

Ambos os códigos fazem a mesma coisa, mas usam API's diferentes do mesmo framework.

É como escrever um componente é _function components e class components em React, ambos fazem a mesma coisa, só muda o como escreve_

No fim das contas o defineComponent é uma coisa do Options API enquanto o defineProps é do Composition API. Na verdade eles sequer são "concorrentes", eles fazem coisas diferentes.

<script setup> VS defineComponent

O defineComponent é o setup inicial do componente, mas um jeito mais verboso de escrever, hoje é possível usar <script setup> que remove a necessidade de escrever esse pedaço de código. No fim o modo mais simples de escrever é usando o setup option do script então acabei usando esse formato ao invés do `define

Component` por questão de comodidade, mas meio que dá pra fazer a mesma coisa com os dois modos.

Aí no caso, você usa defineProps quando estiver em um <script setup> e usa defineComponent quando não estiver num <script setup>, esse método ainda tem a opção de você expor as props através dele.

Eu segui escrevendo tudo usando a Composition API por ser o método mais moderno, ainda no futuro pretendo fazer algo usando a Options API.

Criando um composable

Devo dizer que escrever essa seção faz eu me sentir meio burro, mas faz parte, eu apanhei horrores pra escrever meu primeiro Composable, vale dizer aqui que um composable é basicamente um hook, sério, usa a mesma lógica que vai ser sucesso.

Meu projeto precisava bater em uma API e queria criar um composable que batia na API do github, dava um shuffle dos dados e aí retornava os dados pra o componente.

aqui acabou

Mano o tanto que eu sofri pra fazer isso é sacanagem, mas isso aconteceu porque eu fui, como disse antes, burro!

Primeiro eu tentei dar um await no composable o que, não surpreendentemente, não funcionou, um amigo que conhece Vue disse que o que eu fiz funciona no Vuxt, mas não no Vue normal, mas eu achei um tutorial na internet que poderia salvar minha vida: https://www.vuemastery.com/blog/coding-better-composables-5-of-5/

Poxa, eu vi isso, achei bizarro de funcionar, mas o cara não ia fazer um artigo trolando né? Bom, SE EU TIVESSE LIDO ao invés de ficar tentando copiar os snippets teria sido MUITO BOM, mas eu não li, então eu fiquei coisa de uns 3 dias tentando entender porque quando eu chamava o composable no corpo do componente funcionava, mas quando eu colocava na chamada do método de request ele não ia nem ferrando, bom, isso é porque esse método é apenas pra o setup, não é algo pra eventos ou coisas mais dinâmicas.

Foram dias, até que fiz uma pergunta decente pro GPT e ele mostrou como fazer o composable que, pasmem, era igualzinho um hook do React 😶

Bastava eu retornar os estados e o método de requisição pra o componente que ia funcionar, nada de mais, simples, mas eu fiquei viajando nas minhas próprias ideias de que uma request assíncrona sem await seria resolvida em tempo de execução só porque Deus quer.

Finalmente com uma versão decente do composable eu finalmente tinha ele funcionando conforme eu esperava, já tava tudo praticamente pronto, só faltava isso e o input de texto.

Fiz rapidinho um input de texto e um botão e BOOM, tava funcionando certinho como eu queria 🥹


Considerações finais

Achei bem interessante essa experiência de codar em Vue, quero em breve poder criar algo mais robusto com esse framework que, depois de codar nele, eu ainda amo!

Uma coisa que gostei muito nele é que, mesmo ele tendo mais boilerplate, é muito mais simples de fazer as coisas no Vue e você consegue fazer mais codando menos, isso é bem interessante e algo que eu já imaginava com relação a esse framework maravilhoso!

Tudo em termos de setup foi zero estresse, muito decorrente do boilerplate que escolhi, mas também porque o Vue é um framework simples, algo que ele pega do React de forma incrível, permitindo que reutilizemos esse conhecimento, mas em outro framework!

Pra quem quiser conferir o projeto ele ta aqui e o código ta aqui

Valeu pra quem leu e até a próxima!

Top comments (0)