Este texto é uma livre tradução do artigo do time do Vueschool sobre as novas funcionalidades que irão vir no Vue 3. Então, desde já agradecemos ao excelente artigo escrito por Filip Rakowski que você pode conferir aqui. Vamos ao texto?
No antigo anterior, nós aprendemos sobre as melhorias de performance que Vue 3 irá trazer. Nós já sabemos que apps escritos na nova versão do Vue irão performar melhor mas esta não é a melhor parte. O que mais importa para nós desenvolvedores é como esta nova release irá afetar a forma como nós desenvolvemos.
Como você poderia esperar, Vue 3 traz uma série de novas e emocionantes características. Felizmente, a equipe do Vue introduziu, em vez de grandes mudanças, adições e melhorias nas APIs atuais, para que as pessoas que já conhecem o Vue 2 se sintam à vontade rapidamente com as novas sintaxes.
Vamos começar com a API, você provavelmente já ouviu falar a respeito...
Composition API
Composition API é a syntax feature mais discutida desta nova versão do Vue. É uma abordagem completamente nova para reuso de lógica e organização de código.
Normalmente nós construímos nossos componentes com o que nós chamamos de Options API. Para adicionar lógica aos componentes Vue nós preenchemos propriedades tais como data
, methods
, computed
etc. A maior desvantagem dessa abordagem é o fato de que esse não é como um código JavaScript em si. Você necessita saber exatamente quais propriedades estão acessíveis no templates assim como o comportamento do this
. Por baixo do capô, o compilador Vue precisa transformar estas propriedades em um código funcional. Por causa disso, nós não temos os benefícios de coisas como auto sugestões (autocomplete de editores) ou checagem de tipo (type checking).
A Composition API visa solucionar este problema, expondo os mecanismos atualmente disponíveis nas propriedades do componente como funções JavaScript. O Core Team do Vue descreve a Composition API como "um conjunto de APIs baseadas em funções que permitem composições flexíveis de lógica de componentes". Código escrito usando a Composition API é mais legível e não há mágica por trás, o que faz com seja mais fácil de ler e aprender.
Vamos ver um exemplo simples de um componente que usa a nova Composition API para entender como ela funciona:
<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>
Agora, vamos quebrar este código em algumas partes para entender o que está acontecendo:
import { ref, computed, onMounted } from 'vue'
Como mencionado antes, a Composition API expõe propriedades de componentes como funções, então a primeira etapa é importar as funções de que nós precisamos. Em nosso caso, precisamos criar uma referencia reativa com a função ref
, uma propriedade computada com computed
e acessar o hook de ciclo de vida com onMounted
.
Agora, você provavelmente está se perguntando: o que é este misterioso método setup
?
export default {
setup() {
}
}
Em poucas palavras é apenas uma função que retorna propriedades e funções para o template. É só isso. Nós declaramos todas as propriedades reativas, propriedades computadas, watchers, hooks de ciclo de vida aqui e então retornamos eles para que possam ser usadas no template.
O que não retornamos na função setup não 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
.
const double = computed(() => count.value * 2)
function increment() {
count.value++
}
... e isso é exatamente o que nós fazemos quando declaramos a propriedade computada double
e a função increment
.
onMounted(() => console.log('component mounted!'))
Com o hook onMounted
nós estamos exibindo alguma mensagem quando o componente é montado só para mostrar para você que você pode 😉.
return {
count,
double,
increment
}
No final estamos retornando as propriedades count
e double
com o método increment
para que eles estejam disponíveis no template.
<template>
<button @click="increment">
Count is: {{ count }}, double is {{ double }}. Click to increment.
</button>
</template>
E voila! Agora nós podemos acessar as propriedades e funções retornadas pelo método setup
no template da mesma forma que eles estavam declarados quando da antiga Options API.
Este é um simples exemplo, que poderia ser facilmente realizado com a Options API. O verdadeiro benefício da nova Composition API não é apenas desenvolver de uma forma diferente, os benefícios se revelam quando se trata de reutilizar nosso código/lógica.
Reuso de código com a Composition API
Há mais vantagens na nova Composition API. Vamos falar sobre reuso de código. Normalmente, se nós queremos compartilhar algum código entre componentes há duas opções disponíveis - mixins e scoped slots. Ambos tem suas desvantagens.
Vamos dizer que nós queremos extrair uma funcionalidade chamada counter
e reaproveitá-la em outro componente. Abaixo, você pode ver como poderíamos fazer isso usando as APIs disponíveis e a nova Composition API:
Vamos começar com mixins:
import CounterMixin from './mixins/counter'
export default {
mixins: [CounterMixin]
}
A principal desvantagem dos mixins é o fato de nós não sabermos nada sobre o que eles estão adicionando ao nosso componente. Isso torna não apenas difícil de entender o código, mas também pode levar a colisões de nomes com propriedades e funções existentes.
Agora os scoped slots.
<template>
<Counter v-slot="{ count, increment }">
{{ count }}
<button @click="increment">Increment</button>
</Counter>
</template>
Com scoped slots nós sabemos exatamente quais propriedades nós podemos acessar através da propriedade v-slot
então fica muito mais fácil entender o código. A desvantagem dessa abordagem é que podemos acessá-la apenas em um template
e estar disponível apenas no escopo do componente Counter
.
Agora, vamos ver como fica com a Composition API:
function useCounter() {
const count = ref(0)
function increment () { count.value++ }
return {
count,
incrememt
}
}
export default {
setup () {
const { count, increment } = useCounter()
return {
count,
increment
}
}
}
Muito mais elegante não é? Nós não estamos limitados nem pelo template
nem pelo escopo dos nossos componentes e sabemos exatamente quais propriedades de counter
nós podemos acessar. Adicionado a isso, temos o benefício de termos auto complete do nosso código disponível em nosso editor pois useCounter
é apenas uma função que retorna algumas propriedades. Não há mágica por trás, então o editor pode nos ajudar com checagem de tipo e sugestões.
Também é uma forma mais elegante de usarmos biblioteca de terceiros. Por exemplo, se nós queremos usar o Vuex nós explicitamente usamos a função useStore
ao invés de poluir o protótipo do objeto Vue (this.$store
). Essa abordagem também apaga a mágica dos que acontece nos bastidores dos plug-ins Vue.
const { commit, dispatch } = useStore()
Se você quiser aprender um pouco mais sobre Composition API e seus casos de uso, eu recomendo fortemente ler este documento escrito pelo time do Vue que explica o raciocínio por trás da nova API e sugere os melhores casos de uso dela. Há também este excelente repositório com exemplos de uso da Composition API mantido por Thorsten Lünborg, um membro do core team do Vue.
Mudanças na API de montagem/configuração global
Nós encontramos outra mudança grande na forma que nós instanciamos e configuramos nossa aplicação. Vamos ver como isso irá ficar:
import Vue from 'vue'
import App from './App.vue'
Vue.config.ignoredElements = [/^app-/]
Vue.use(/* ... */)
Vue.mixin(/* ... */)
Vue.component(/* ... */)
Vue.directive(/* ... */)
new Vue({
render: h => h(App)
}).$mount('#app')
Atualmente nós usamos o objeto global do Vue para nos prover qualquer configuração e criar novas instâncias do objeto Vue. Qualquer mudança feita num objeto Vue irá afetar todas as outras instâncias e componentes.
Agora, vamos ver como isso irá funcionar no Vue 3:
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.config.ignoredElements = [/^app-/]
app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)
app.mount('#app')
Como você provavelmente percebeu agora, todas as configurações têm o escopo definido para uma determinada aplicação Vue definida com a função createApp
.
Atualmente, se alguma solução de terceiros estiver modificando o objeto Vue, ela poderá afetar sua aplicação de maneiras inesperadas (especialmente com mixins globais), o que não será possível com o Vue 3.
Esta mudança de API está sendo discutida atualmente neste RFC, o que significa que potencialmente poderá mudar no futuro.
Fragments
Outra emocionante adição que nós podemos esperar no Vue 3 são os fragmentos.
O que são fragmentos? Bem, se você criar componentes Vue, eles só podem ter apenas um nó central.
Isso significa que um componente como este não poderá ser criado:
<template>
<div>Hello</div>
<div>World</div>
</template>
A razão para isso é que a instância do Vue que representa qualquer componente Vue precisa ser vinculado a um único elemento DOM. A única forma que você tem para criar um componente com múltiplos nós DOM é criando um componente funcional que não tem fundamento na instância do Vue.
Acontece que a comunidade React teve o mesmo problema. A solução que eles trouxeram foi criar um elemento virtual chamado Fragment
. Parece mais ou menos assim:
class Columns extends React.Component {
render() {
return (
<React.Fragment>
<td>Hello</td>
<td>World</td>
</React.Fragment>
);
}
}
Apesar de Fragments
se parecerem com um elemento DOM normal eles são virtuais e não serão renderizados na árvore DOM. Dessa forma, podemos vincular a funcionalidade do componente em um único elemento sem criar um nó DOM redundante.
Atualmente nós podemos usar Fragments
no Vue 3 com a biblioteca vue-fragments e no Vue 3 você os terá pronto para usar!
Suspense
Outra grande ideia do ecossistema React que será adotado pelo Vue é o componente Suspense
.
Suspense
suspenderá a renderização de seu componente e renderizará um componente fallback* até que uma condição seja atingida. Durante a Vue London, Evan You tocou brevemente neste tópico e nos mostrou a API que mais ou menos podemos esperar. Acontece que o Suspense
será apenas um componente com slots:
<Suspense>
<template >
<Suspended-component />
</template>
<template #fallback>
Loading...
</template>
</Suspense>
Um conteúdo de fallback* será exibido até que o componente Suspended-component
seja inteiramente renderizado. Suspense
pode esperar até o download do componente, se for um componente assíncrono, ou executar algumas ações assíncronas na função setup
.
Múltiplos v-models
v-model
é uma diretiva que nós usamos para realizar um two-way data binding em um dado componente. Nós podemos passar uma propriedade reativa e modificá-la de dentro de um componente.
Conhecemos bem o v-model
pelo seu uso em componentes de formulário.
<input v-model="property />
Mas você sabia que pode usar o v-model
com cada componente? Por baixo do capô ele é apenas um atalho para um mecanismo de passar uma propriedade value
e ouvir um evento input
. Reescrevendo o exemplo acima para a sintaxe abaixo teremos o mesmo efeito:
<input
v-bind:value="property"
v-on:input="property = $event.target.value"
/>
Nós ainda podemos alterar o nome padrão das propriedades e os nomes dos eventos com a propriedade model
do componente.
model: {
prop: 'checked',
event: 'change'
}
Como você pode ver a diretiva v-model
pode nos dar um açucar sintático muito útil quando queremos ter um two-way data binding em nossos componentes. Infelizmente você só pode ter apenas um v-model
por componente.
Felizmente, isso não será um problema no Vue 3! Você poderá dar nomes às propriedades do v-model
e ter quantas delas desejar. Abaixo você encontra um exemplo de dois v-model
s em um componente de formulário:
<InviteeForm
v-model:name="inviteeName"
v-model:email="inviteeEmail"
/>
Esta mudança na API está atualmente sendo discutida neste RFC o que significa que potencialmente poderá mudar no futuro.
Portals
Portais são componentes especiais determinados a renderizar certo conteúdo fora do componente atual. É também uma feature nativamente implementada no React. Isso é o que a documentação oficial do React diz sobre os portais:
"Os portais fornecem uma maneira first-class de renderizar filhos em um nó DOM que existe fora da hierarquia DOM do componente pai."
É uma maneira muito interessante de lidar com modais, popups e outros componentes que geralmente aparecem no topo da página. Ao usar portais, você pode ter certeza de que nenhuma das regras CSS do componente pai afetará o componente que você deseja exibir e o isentará de executar hacks desagradáveis com o z-index
.
Para cada portal precisamos especificar qual o destino alvo onde o conteúdo do portal será renderizado. Abaixo você pode ver uma implementação da biblioteca portal-vue que adiciona essa funcionalidade ao Vue 2.
<portal to="destination">
<p>This slot content will be rendered wherever thportal-target with name 'destination'
is located.</p>
</portal>
<portal-target name="destination">
<!--
This component can be located anywhere in your App.
The slot content of the above portal component wilbe rendered here.
-->
</portal-target>
O Vue 3 terá suporte nativo aos portais!
Nova API para diretivas customizadas
Diretivas customizadas irão mudar superficialmente no Vue 3 para melhor se alinhar com o ciclo de vida dos componentes. Esta mudança poderá tornar a API mais fácil de se entender e aprender para iniciantes, pois será mais intuitiva.
Esta é a API atual:
const MyDirective = {
bind(el, binding, vnode, prevVnode) {},
inserted() {},
update() {},
componentUpdated() {},
unbind() {}
}
... e isto é como ela irá se parecer no Vue 3:
const MyDirective = {
beforeMount(el, binding, vnode, prevVnode) {},
mounted() {},
beforeUpdate() {},
updated() {},
beforeUnmount() {}, // new
unmounted() {}
}
Mesmo sendo uma breaking change, ela deve ser facilmente coberta com uma ferramenta de compatibilidade do Vue.
Esta mudança na API está atualmente sendo discutida neste RFC o que significa que potencialmente poderá mudar no futuro.
Psst! Você pode aprender como dominar diretivas customizas em nosso curso.
Sumário
Além da Composition API, que é a maior e mais nova API do Vue 3, também podemos encontrar muitas melhorias menores. Podemos ver que o Vue está caminhando para uma melhor experiência de desenvolvimento e uma API mais simples e intuitiva. Também é bom ver que a equipe do Vue decidiu adotar muitas idéias que estão disponíveis atualmente apenas através de bibliotecas de terceiros para o núcleo do framework.
A lista acima contém apenas as principais alterações e melhorias da API. Se você estiver curioso sobre outras, verifique o repositório de RFCs do Vue.
Bom, está é a tradução. Espero que tenha gostado. Não deixe de compartilhar este post para que mais pessoas o encontrem e se surpreendam com as mudanças bastante positivas que o time do Vue está trazendo.
Até a próxima!
Top comments (4)
Muitos vão dizer que o vue está se "reactirizando". Porém n vejo problema em usar o que já é legal/bom/ótimo se espelhando em outros(reactjs).
Que venha pleno o vue3!
Com certeza... De certa forma até que sim, mas até o momento não vejo problema nisso, porque faz parte da evolução do ecossistema de frameworks JavaScript. Que venha o Vue 3!
Não há como negar que o Vue 3 terá seu pezinho dentro do react, todavia, excluindo o fato do "super fan boy", vue, desde sua criação, sempre foi muito mais semanticamente organizado, estruturado e robusto do que react, e portanto, ainda que haja tais implementações baseadas no React, não acredito no "downgrade" do framework e sim no super poder de produção que ele nos trará.
Agora aguardar vim !!