Vue.js | '$emit()': uma solução interessante para comunicação de eventos e funções entre os componentes.
Olá, essa é minha primeira publicação no TabNews!
Antes da primeira publicação, acho importante deixar algumas das minhas ideias expressadas.
Decidi criar sobre o Vue e não React por uma razão simples, eu já estudo e pratico React.js a um bom tempo, a quantidade de informação sobre o mesmo é muito grande, Talvez pelo algoritmo das minhas pesquisas mas isso não importa. O que importa foi minha decisão de aprender uma Ferramenta nova.
Atualmente estou quase terminando de Ler toda a documentação do Vue.js, Ler a documentação de ponta a ponta é o método de aprendizagem mais eficaz, claro, depois de uma boa base de HTML, CSS e Javascript e um tempo de experiência, recomendo isso para todos os desenvolvedores que compartilho ideias e informações.
Minha motivação é o compartilhamento de conhecimentos, sejam eles básicos ou avançados
Agora vamos de código!
Vamos falar sobre a emissão e escuta de eventos $emit()
(que eu posso fazer uma publicação aqui se eu tiver algum feedback construtivo sobre essa postagem)
De primeira, vamos entender a situação e porque se usa o $emit()
, a ordem será: situação -> código -> explicação do que está acontecendo.
1 - Temos um card com detalhes sobre um serviço na nossa página e queremos um botão toggle que abra e fecha esse card, porém este mesmo card está em um componente/sessão separado do componente com o botão "Detalhes" dentro da página "Nossos Serviços".
NossosServicos.vue:
PascalCase
<ComponenteCard />
<ComponenteComBotao />
kebab-case
<componente-card />
<componente-com-botao />
Por padrão irei usar a escrita PascalCase. mas vale ressaltar que o Vue.js transforma tudo em kebab-case por padrão
components/ComponenteCard.vue
defineProps({ isEnabled: Boolean })
...
<div v-if="isEnabled">
<p>Detalhes</p>
</div>
...
components/ComponenteComBotao.vue
...
<button @click="$emit('isEnabled')">Detalhes</button>
...
Observe que no ComponenteCard.vue nós temos uma propriedade booleana que está verificando se aquela div vai aparecer na tela ou não e no ComponenteComBotao.vue nós temos um botão com evento click e nele chamamos a função $emit('isEnabled').
Para fazer funcionar essa comunicação é simples, na página NossosServicos.vue adicionamos uma variável reativa para ser alterada e enviada pelos componentes:
...
const isEnabledDetails = ref(false)
...
<ComponenteCard :isEnabled="isEnabledDetails" />
<ComponenteComBotao @isEnabled="() => isEnabledDetails = !isEnabledDetails" />
E pronto, está funcionando o toggle. Mas eaí? O que ta rolando? Como funciona?
Bom, de forma resumida (por favor Leia as páginas da documentação para ter uma compreensão completa sobre o que se acontece, pois irei resumir de uma forma amigável para todos entenderem)
Ao colocar a função $emit('isEnabled')
dentro do evento clique do botão no ComponenteComBotao.vue, automaticamente o Vue.js reconhece a função $emit e o componente deve receber um "atributo" v-on:isEnabled=""
ou abreviando @isEnabled=""
, e dentro deste atributo você irá adicionar sua função. Assim, sempre que o botão com o emit isEnabled for clicado, ele irá rodar a função.
2 - Temos um formulário que irá preencher um template de documento. De um lado o formulário com os <input>
s necessários para preencher o documento, e do outro, o documento impresso atualizando em tempo real de acordo que você preenche o formulário, mas para o código ficar curto, vamos mostrar apenas com um input.
Neste caso, a sessão de <script></script>
do Vue.js não teria acesso ao emit. Então nós podemos definir que o emit irá retornar um valor de uma propriedade. Aqui temos 2 opções
components/ComponenteFormulário.vue
Primeira opção: usando a função 'computed', que básicamente fica escutando um evento ou valor ser alterado para executar uma função (um pouco semelhante ao useEffect() hook do React.js) e nós a v-model para enviar o que for digitado do <input>
para a variavel que chama a função computed()
'
<script setup>
import { computed } from 'vue'
defineProps(['algumValor'])
defineEmits(['update:algumValor'])
const value = computed({
get() {
return props.value
},
set(value) {
emit('update:algumValor', value)
}
})
</script>
<template>
<input v-model="value">
</template>
segunda opção: Chamar a função $emit
diretamente do evento do <input>
utilizando v-on:input
ou @input
que é um listener para quando tiver uma alteração ou digitação dentro do nosso input, sem a necessidade de definir as props e os emits no <script></script>
Quando chamamos a função $emit() com update: antes do nome que definimos ao emit 'algumValor', nós retornamos esse valor passando como segundo argumento o valor que será retornado
<template>
<input @input="$emit('update:algumValor', $event.target.value)">
</template>
Ambas as opções são válidas, tudo depende do que você está precisando, é apenas enviar um dado ou esse dado antes de ser enviado precisa passar por uma validação? Tudo depende das necessidades da sua feature.
Agora Para fazer funcionar essa comunicação entre os componentes na página é mais simples ainda:
AssinarDocumento.vue
<script setup>
...
const isEnabledDetails = ref(false)
...
</script>
<template>
<AssinarDocumento v-model:algum-valor="inputValue"/>
<TemplateDocumento :formDataProps="inputValue"/>
</template>
Observe que o Vue.js transforma tudo em kebab-case, então mesmo se declararmos algo em camelCase ou PascalCase, ele transformará em kebab-case, porém ambos funcionam:
<input @input="$emit('update:algumValor', $event.target.value)">
<AssinarDocumento v-model:algum-valor="inputValue"/>
ou
<AssinarDocumento v-model:algumValor="inputValue"/>
Conclusão: Em meus estudos e minha jornada de ler a doc de ponta a ponta, vi que o Vue.js encontrou soluções muito interessantes de uma forma mais simplificada e amigável para a compreensão.
A sensação que tenho em ter programado em React.js anteriormente e estar estudando e programando em Vue.js hoje, é de que o Vue.js encontrou uma sintaxe semelhante as Linguagens HTML, CSS e Javascript que para quem domina essas 3 ferramentas no 'Vanilla', a curva de aprendizado é bem mais rápida e simplificada, enquanto tenho uma sensação de o React.js foi mais pretencioso em relação a robustez da ferramenta.
Bom pessoal, espero ter contribuído de alguma forma ou ter tirado alguma duvida para essa comunidade.
Me perdoem se eu tiver errado em alguma escrita ou se alguma explicação ficou confusa. Por favor Dêem feedback, comentem e propaguem informação!
Mas comentem aí, o que acharam?