7 dicas do Vue3 que você precisa saber
Originalmente postado por Roland Doda - DEV Community
- VNode hooks
- Debugging hooks
- Expor slots de um componente filho
- Estilos com escopo e nós múltiplos não funcionam bem juntos
- Tenha cuidado ao usar seletores CSS
- Conversão booleana
- Template refs com v-for - a ordem não é garantida
VNode hooks
Em cada componente ou tag HTML, podemos usar alguns hooks especiais (não documentados) como ouvintes de eventos. Os hooks são:
onVnodeBeforeMountonVnodeMountedonVnodeBeforeUpdateonVnodeUpdatedonVnodeBeforeUnmountonVnodeUnmounted
Eu principalmente uso onVnodeMounted em componentes quando preciso executar algum código quando o componente é montado ou onVnodeUpdated para depurar quando algo é atualizado, mas tenho certeza de que todos eles podem ser úteis em alguns casos.
Exemplo:
<script setup>
import { ref } from 'vue'
const count = ref(0)
function onMyComponentMounted() {}
function divThatDisplaysCountWasUpdated() {}
</script>
<template>
<MyComponent @vnodeMounted="onMyComponentMounted" />
<div @vnodeUpdated="divThatDisplaysCountWasUpdated">{{ count }}</div>
</template>
Deve-se notar que esses hooks passam alguns argumentos para a função de callback. Eles passam apenas um argumento que é o VNode atual, exceto para onVnodeBeforeUpdate e onVnodeUpdated que passam dois argumentos, o VNode atual e o VNode anterior.
Debugging hooks
Todos nós conhecemos os lifecycle hooks que o Vue nos fornece. Mas você sabia que o Vue 3 nos oferece dois hooks que podemos usar para fins de depuração? Eles são:
onRenderTracked é chamado para cada dependência reativa que foi rastreada.
<script setup>
import { ref, onRenderTracked } from 'vue'
const count = ref(0)
const count2 = ref(0)
// Será chamado duas vezes, uma vez para count e uma vez para count2
onRenderTracked((event) => {
console.log(event)
})
</script>
onRenderTriggered é chamado quando acionamos uma atualização de reatividade, ou como a documentação diz: “quando uma dependência reativa dispara o efeito de renderização do componente para ser executado novamente”.
<script setup>
import { ref, onRenderTriggered } from 'vue'
const count = ref(0)
// Será chamado quando atualizarmos count
onRenderTriggered((event) => {
debugger
})
</script>
Expor slots de um componente filho
Se você usar um componente de terceiros, é provável que você envolva a implementação dele em seu próprio componente “wrapper”. Esta é uma boa prática e uma solução escalável, mas dessa forma, os slots desse componente de terceiros são perdidos e devemos encontrar uma maneira de expô-los ao componente pai:
WrapperComponent.vue
<template>
<div class="wrapper-of-third-party-component">
<ThirdPartyComponent v-bind="$attrs">
<!-- Expor os slots do componente de terceiros -->
<template v-for="(_, name) in $slots" #[name]="slotData">
<slot :name="name" v-bind="slotData || {}"></slot>
</template>
</ThirdPartyComponent>
</div>
</template>
Agora todo componente que usa WrapperComponent pode usar os slots de ThirdPartyComponent
.
Estilos com escopo e nós múltiplos não funcionam bem juntos
No Vue 3 finalmente podemos ter componentes com mais de “um nó raiz”. Isso é ótimo, mas pessoalmente me deparo com uma limitação de design ao fazer isso. Imagine que temos um componente filho:
<template>
<p class="my-p">Primeiro p</p>
<p class="my-p">Segundo p</p>
</template>
E um componente pai:
<template>
<h1>Meu componente incrível</h1>
<MyChildComponent />
</template>
<style scoped>
// Não há maneira de estilizar as tags p do MyChildComponent
.my-p { color: red; }
:deep(.my-p) { color: red; }
</style>
Não há maneira do estilo com escopo do componente pai com múltiplos nós raiz de estilizar as tags p do componente filho.
Em resumo, um componente com múltiplos nós raiz não pode direcionar estilos de componentes filhos com múltiplos nós raiz com estilos com escopo.
A melhor maneira de corrigir isso seria envolver o componente pai ou filho (ou ambos) para que tenhamos apenas um elemento raiz.
Mas se você absolutamente precisa que ambos tenham múltiplos nós raiz, você pode:
- Usar um estilo sem escopo
<style>
.my-p { color: red; }
</style>
- Usar CSS Modules
<template>
<h1>Meu componente incrível</h1>
<MyChildComponent :class="$style.trick" />
</template>
<style module>
.trick {
color: red;
}
</style>
Como estamos especificando uma classe aqui, o componente filho com múltiplos nós raiz deve especificar explicitamente o comportamento de fallthrough de atributos.
Se você quer minha opinião, a menos que você absolutamente precise de um componente com múltiplos nós raiz, vá com um nó raiz único e não lide com essa limitação de design.
Tenha cuidado ao usar seletores CSS
#main-nav > li {} será muitas vezes mais lento comparado a .my-li { color: red }. Da documentação:
Devido à forma como os navegadores renderizam vários seletores CSS, p { color: red } será muitas vezes mais lento quando com escopo (ou seja, quando combinado com um seletor de atributo). Se você usar classes ou ids em vez disso, como em .example { color: red }, você praticamente elimina esse impacto de desempenho.
Eu recomendo fortemente que você leia Efficiently Rendering CSS se quiser se aprofundar neste tópico.
Conversão booleana
No Vue 2 ou nas primeiras versões do Vue 3, para props com tipos Boolean tínhamos comportamentos diferentes dependendo da ordem:
1º caso:
props: {
hoverColor: [String, Boolean] // <- padrão é ''
}
2º caso:
props: {
hoverColor: [Boolean, String] // <- padrão é false
}
Não apenas isso, mas se você passar a prop assim:
<my-component hover-color></my-component>
No primeiro caso, seria uma string vazia ''. No segundo caso, seria true.
Como você pode ver, isso era um pouco confuso e inconsistente. Felizmente, no Vue 3, temos um novo comportamento que é consistente e previsível:
O comportamento de
Booleanserá aplicado independentemente da ordem de aparição do tipo.
Então:
hoverColor: [String, Boolean] // <- padrão é false
hoverColor: [Boolean, String] // <- padrão é false
hoverColor: [Boolean, Number] // <- padrão é false
Template refs com v-for - A ordem não é garantida
lembre-se disso para não perder horas depurando tentando descobrir o que está acontecendo
No código abaixo:
<script setup>
import { ref } from "vue";
const list = ref([1, 2, 3]);
const itemRefs = ref([]);
</script>
<template>
<ul>
<li v-for="item in list" ref="itemRefs" :key="item">
{{ item }}
</li>
</ul>
</template>
estamos iterando sobre o array list e criamos o array itemRefs.
**itemRefsnão é garantido ter a mesma ordem que o array list.
Se você quiser saber mais sobre isso, você pode ler esta issue.
Finalizando o artigo
Eu tenho mais dicas e truques, mas este artigo ficou longo demais. Espere por outro artigo em breve com dicas/truques ainda melhores.
Obrigado a todos por lerem, qualquer feedback é muito apreciado!
Conhece uma empresa legal contratando desenvolvedores Vue.js?
Além disso, estou procurando um novo emprego, então se você conhece uma empresa legal que está contratando um desenvolvedor Vue.js sênior, entre em contato comigo em rolanddoda2014@gmail.com
.