Atualmente o Vue é um dos frameworks mais populares dentro do mundo do desenvolvimento web, já que é um framework muito amigável, com grande facilidade de escrita e leitura. Nesse artigo vamos conhecer as novidades de sua atualização mais recente, o Vue 3, além de responder uma dúvida muito comum: “Com a chegada do Vue 3 vou precisar reaprender tudo que eu sei?”

Por enquanto vou apenas comparar as diferenças entre o Vue 2 e Vue 3, dessa forma, por enquanto, não vou abordar temas como Teleport e Fragment não vão ser abordadas.

Vue.createApp()

No Vue 2, quando queríamos criar um elemento data, methods ou função computada precisávamos criar uma nova instância do Vue:

new Vue({
  data: {...},
  methods: {...},
  computed: {...}
  ...
})

Porém, isso mudou no Vue 3. Agora temos diversas funções importadas do próprio Vue, como o createApp, que fazem alguns trabalhos que antes fazíamos manualmente.

import { createApp } from "vue";
Vue.createApp()

Na prática, será feito exatamente o mesmo que antes, mas de uma forma mais próxima do JavaScript, o que é ótimo. Mas não é só! Dentro da função precisamos colocar os elementos do componente e isso vai acontecer exatamente como era antes. Veja o exemplo:

import { createApp } from "vue";

const app = Vue.createApp({
  data() {
    return {
      ...
    }
  },
  methods: {...},
  computed: {...}
  ...
})

Dessa forma, o Vue fica semelhante a outros Frameworks, pois tem funções próprias para realizar diversas tarefas na aplicação, deixando o fluxo e leitura mais fáceis.

data()

A nova forma de declarar a instância do Vue transforma a propriedade data em uma função. Antes já era possível fazer assim, mas agora é obrigatório. Consequentemente, o código muda um pouco, por exemplo:

data() {
    return {
      ...
}

Mas é apenas uma mudança pontual, não precisa perder horas tentando entender.

app

Antes, quando queríamos usar alguma biblioteca externa ou acessar um componente, usávamos a partir da instância do Vue diretamente. No entanto, agora não é algo tão recomendado. Ao invés disso, devemos acessar a partir de uma constante (normalmente chamada app), por exemplo:

import { createApp } from "vue";
import App from './App.vue'

const app = Vue.createApp(App)

app.use()
app.component()
app.mount()

Como resultado, temos um controle bem mais claro e direto. Não precisamos mais chamar aquele trecho gigante só para dizer que o Vue vai usar uma rota ou que ele tem que montar algo na tela, basta chamar o app e a função logo depois. Isso não é obrigatório, mas é algo bem legal de se trabalhar.

Rotas

Da mesma forma como eu mostrei lá no createApp, aqui também vamos importar uma função que vai fazer a configuração inicial. Então, inicialmente precisamos fazer o seguinte:

import { createRouter } from "vue-router"

Agora, vamos poder usar a função e atribui-la a uma constante chamada router

const router = createRouter()

Precisamos colocar a configuração das rotas, e isso não é muito diferente do que já conhecemos do Vue 2, por exemplo:

const router = createRouter({
	routes: [
		{ path: '/', component: Home },
		{ path: '/about', component: About },
	],
})

A configuração de history também mudou um pouco, pois ela também vai ser uma função que vai fazer toda a configuração, basta importar e chamá-la dentro da criação da rota:

const router = createRouter({
	history: createWebHistory(),
	routes: [
		{ path: '/', component: Home },
		{ path: '/about', component: About },
	],
})

Dessa forma, o código completo fica assim:

import { createApp } from "vue"
import { createRouter, createWebHistory } from "vue-router"
import App from './App'

const router = createRouter({
	history: createWebHistory(),
	routes: [
		{ path: '/', component: Home },
		{ path: '/about', component: About },
	],
})

const app = createApp(App)
app.use(router)

De tal forma que, comparando com o Vue 2, dá para perceber que que não mudou muita coisa:

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const router = new VueRouter({
  mode: 'history',
  routes: [
	{ path: '/', component: Home },
	{ path: '/about', component: About }
  ]
})

Vuex – Criando Store

A maneira clássica de se criar uma store no Vuex é a seguinte:

const store = new Vuex.Store({
//Configuração Store (getters, mutations, actions, state e etc)
})

new Vue({
	store: store
}).$mount('#app')

Já no Vue 3, faremos como apresentado até agora, ou seja, vamos importar uma função responsável e apenas configurá-la. Portanto, o primeiro passo é importar a função:

import { createStore } from "vuex"

Em seguida, criaremos uma constante que vai receber a função. Para ficar mais claro, nomearei a função de store.

const store = createStore()

Essa é a forma básica, mas ainda precisamos passar a configuração. Isso é bom, porque funciona como as rotas. O que já existe é funcional, então vamos colocar nossos getters, mutations, actions e tudo mais lá dentro. O código completo fica assim:

import { createApp } from 'vue'
import { createStore } from 'vuex'

import App from './App.vue'

const store = createStore({
//Configuração Store (getters, mutations, actions, state e etc)
})

const app = createApp(App)
app.mount('#app')

Composition API

Essa é a parte mais legal do Vue 3, pois com ele chegou uma nova abordagem para reuso de lógica e organização de código dentro do Vue.

Normalmente, construímos nossos componentes com Options API, como no código abaixo:

new Vue({
  data: {...},
  methods: {...},
  computed: {...}
  ...
})

A desvantagem dessa abordagem é que esse não é como um código JavaScript em si. Você precisa saber exatamente quais propriedades estão acessíveis no templates, assim como o comportamento do this. Na prática, o compilador precisa transformar estas propriedades em um código funcional e pensando nisso temos essa belezinha.

É importante saber que Composition API é completamente opcional, se quiser você pode continuar utilizando o modo padrão que ele funciona perfeitamente.

Agora um exemplo de implementação do novo Composition API:

<template>
  <button @click="increment">
    Count is: {{ count }}, double is {{ double }}, click to increment.
  </button>
</template>

<script>
import { ref, computed, onMounted } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const double = computed(() => count.value * 2)

    function increment() {
      count.value++
    }

    onMounted(() => console.log('component mounted!'))

    return {
      count,
      double,
      increment
    }
  }
}
</script>

A primeira coisa que chama atenção nessa nova forma é o import do ref, computed e onMounted

import { ref, computed, onMounted } from "vue"

Elas funcionam como as antigas propriedades que tínhamos no Vue 2, no entanto agora o Vue exporta essas propriedades como funções que são utilizadas no componente. No exemplo usaremos uma referência reativa com ref, também vamos precisar de uma propriedade computada por isso do computed e um ciclo de vida, por isso o onMounted.

Próximo ponto de interesse é descobrir para que serve essa função setup:

export default {
  setup() {
  }
}

Basicamente, ela é a responsável por criar e retornar todas as propriedades e funções que usaremos dentro do nosso template (nisso se encaixa watcher, computed, hooks de ciclo de vida). O que não for retornado não vai estar disponível no template.

const count = ref(0)

No código acima, nós declaramos uma propriedade reativa chamada count usando a função ref. Ela pode encapsular qualquer valor primitivo ou objeto e retorná-lo como uma propriedade. O valor passado será mantido na propriedade value da referência criada. Por exemplo, se você quiser acessar o valor de count, você precisa explicitamente chamar por count.value.

Agora, para utilizarmos as nossas funções computadas ou apenas funções normais basta fazer o seguinte:

const double = computed(() => count.value * 2)

function increment() {
  count.value++
}

O mesmo se aplica para hooks de ciclo de vida:

onMounted(() => console.log('componente montado!'))

Por fim vamos fazer o processo mencionado acima, no qual consiste em retornar as propriedades que o template vai poder ter acesso

return {
  count,
  double,
  increment
}

Assim podemos utiliza-los dessa maneira:

<template>
  <button @click="increment">
    Count is: {{ count }}, double is {{ double }}. Click to increment.
  </button>
</template>

Com isso um dos conceito mais complexo do Vue 3 foi destrinchado.

Conclusão

Esses foram as mudanças entre Vue 2 e Vue 3 que eu considero mais importantes. Voltando a pergunta do início… “Com a chegada do Vue 3 vou precisar reaprender tudo que eu sei?”.

A resposta é sim. Apesar de muita coisa ter sido alterada, a estrutura base permanece a mesma e usa dos mesmos conceitos, e se você sabe JavaScript provavelmente ficou melhor ainda, pois a maneira de criar tudo se aproxima muito mais da linguagem mais pura.

Espero que tenham entendido o que passei aqui e fiquem atentos a todas as nossas plataformas para mais conteúdos legais como esse 😉

Referências

Differences Between Vue 2 And Vue 3

Exciting new features in Vue 3