Vue Primeiras Impressões
Tags: javascript, vue, typescript, css
Published: 2024-02-20 15:56:56

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](https://www.youtube.com/watch?v=KrPz_wmBsAE), 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](https://caniuse.com/mdn-css_properties_grid-template-rows_masonry) 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/smkstipm0qj75f5s9m2n.png)

_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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/34du1lt29vyqxv82drm1.png)

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

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

```css
.container {
  column-count: auto;
  column-gap: var(--masonry-spacing);
  column-width: 210px;
}
```

`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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2d23vwltrnprtl028d73.png)

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](https://vuejs.org/) 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2obzz0akgvwihbf72l1v.png)

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

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

<template>
  <!-- uso a propriedade -->
  <span>{{ name }}</span>
</template>
```

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`

```vue
<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>
```
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

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

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

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

  const changeName = function(newName) {
    name.value = newName
  }
</script>
```

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](https://alecell.github.io/masonry-github-contrib/) e o código [ta aqui](https://github.com/Alecell/masonry-github-contrib) 

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