-
-
Save reginadiana/738c30a4671027175e7cc40746bb0b8e to your computer and use it in GitHub Desktop.
Assim como todo framework que se preze, o Vue conta com um guia de boas práticas (também chamado de style guides) e eles são essenciais para aproveitar o melhor que ele tem a oferecer e entender porque certas decisões foram tomadas na sua construção, ainda que a própria documentação cite que elas podem ser adaptadas ao contexto do projeto de forma consciente.
O guia contém 4 partes, divididas em uma hierarquia de regras por ordem de importância, que também podem ser interpretadas por ordem de flexibilidade, já que quanto menos importantes, mais liberdade o desenvolvedor tem de segui-las, desde que ele tenha conhecimento do que está fazendo. São elas: essenciais, fortemente recomendadas, recomendadas, e as que podem até ser quebradas, mas com cautela.
São regras que evitam erros, então é muito importante que elas sejam seguidas.
Pode parecer demais, mas é uma boa prática nomear os componentes indicando onde ele está inserido. Por exemplo:
// Melhor não fazer isso
export default {
name: "List"
}
// Prefira
export default {
name: "MenuList"
}
Isso é necessário pois quando vamos usar um componente em <template>
queremos evitar o conflito entre outras tags, e como uma lista é algo genérico, ela pode estar inserida em vários contextos.
Dentro de um componente, data é onde declaramos os dados globais para aquele componente, e mesmo que ele seja reutilizado, esses dados devem ser alterados conforme o contexto em que foram instanciados e não devem ter ligação alguma com outras instancias.
O que acontece, é que quando declaramos esse data como um objeto, ele é compartilhado em todas as instancias daquele componente, ou seja, os dados não são modificados apenas internamente no contexto em que foi chamado, mas sim por todas as outras instancias.
// Melhor não fazer isso
export default {
data: {
position: 0
}
}
Por exemplo: em uma página nós temos um menu que controla qual imagem deve aparecer no carrossel, mas decidimos reaproveitar esse componente para criar outro carrossel. Usando o data como objeto, toda vez que mudarmos a posição pelo menu de um carrossel, o outro também mudará, pois esses dados estão sendo compartilhados.
O correto seria que ao manipular um menu, o outro não se altere apesar de ser o mesmo componente, pois o contexto é diferente:
// Podemos declarar assim
export default {
data: function() {
return {
position: 0
}
}
}
// Ou assim, ambos são funções
export default {
data() {
return {
position: 0
}
}
}
Props são dados compartilhados entre componentes pais e filhos, e uma das coisas interessantes que o Vue nos trás é poder detalhar sobre quais props estão chegando, como uma especie de documentação mesmo. Por isso é recomendado que se defina pelo menos o seu tipo, assim o Vue emitirá um alerta indicando que o dado não chegou no formato correto. Exemplo:
// Melhor não fazer isso, pode vir qualquer coisa
export default {
props: ['position']
}
// Prefira detalhar a props
export default {
props: {
position: {
type: String,
required: true
...
}
}
}
Para saber mais, acesse a sobre as props na documentação do Vue, lá eles falam sobre os tipos de dados que podem ser compartilhados, dados default, validações e outros.
Toda vez que for usar o v-for
para renderizar o conteúdo de um objeto ou lista, sempre defina uma key
para cada um dos elementos renderizados. Para saber mais sobre o porquê, recomendo o artigo do Marko Burazin - How & Why to use the :key
attribute in VueJS v-for loop
<template>
<div>
<div v-for="(item, key) in list" :key="key">
<h1>{{ item }}</h1>
</div>
</div>
</template>
É muito comum estar diante de uma situação em que precisamos renderizar condicionalmente uma informação, como por exemplo:
-
Mostrar apenas os filmes disponiveis em cartaz;
-
Mostrar apenas os planos ativos de uma academia;
-
Mostrar apenas os boletos pagos no sistema.
Diante desses cenários, ficamos tentados a usar o v-if
junto com o v-for
, porém isso é um problema pois toda vez que aquele componente for renderizado, será verificado para cada item da lista/objeto se ele safisfaz a condição.
Nesses casos, prefira usar dados computados (computed), pois sua responsabilidade é retornar um dado a partir de outros após algum tipo de tratamento. O "tratamento", neste caso, será o filtro, gerando beneficios como:
-
Toda vez que o componente for renderizado, não será necessário que todos os itens passem pelo
if
novamente. -
O filtro só será feito se o conteúdo do objeto/lista mudar.
-
Podemos remover essa lógica do html.
<template>
<div>
<!-- Evite -->
<div v-for="(movie, key) in releasedMovies" :key="key" v-if="movie.released">
<h1>{ { movie.title } }</h1>
</div>
</div>
</template>
<template>
<div>
<!-- Prefira -->
<div v-for="(movie, key) in releasedMovies" :key="key">
<h1>{ { movie.title } }</h1>
</div>
</div>
</template>
<script>
export default {
computed: {
releasedMovies() {
return this.movies.filter(({ released }) => released)
}
}
}
</script>
Outro ponto sobre o Vue é sobre estilos isolados, chamados de scoped. Isso significa que é possível declarar estilos do zero para cada componente, sem serem sobrescritos pelos pais e sem sobrescrever os filhos.
Por isso, o nome das classes podem ser mais clean pois ao declarar uma mesma classe em 5 componentes usando scoped, nenhum estilo sofrerá conflito. Isso ajuda bastante na manutenção e refatoração do css pois os estilos são internos ao componente e não "vazam" para outros.
É claro que existem casos em que queremos aproveitar algum estilo padrão para botões, listas, etc, por isso, prefira ter arquivos isolados para esses estilos e importá-los nos seus componentes quando necessário.
<style lang="scss" scoped>
@import "../assets/button.scss"; // Reaproveitado os estilos desse arquivo
.modal__title {
color: pink; // Esse estilo e classe só serão usados nesse componente
}
</style>
Dentro da tag <script>, usamos partes como data(), mounted(), props, dentre tantas outras que devem ser chamadas em uma ordem, a fim de manter a organização e padronização. São eles:
el
name
parent
functional
delimiters
comments
components
directives
filters
extends
mixins
inhiattrs
model
props
data
computed
watch
beforeCreate
created
beforeMounted
mounted
beforeUpdate
updated
activated
deactivated
beforeDestroy
destroyed
methods
template/render
renderError
A seguir apresento outros patterns/dicas de boas práticas que encontrei lendo artigos na internet ou assistindo palestras:
-
Não use o
index
comokey
ao interar elementos que podem mudar a ordem. Ao invés disso, podemos usar o próprioid
. -
Lifecycle hooks são métodos de ciclo de vida dos componentes
mounted
,updated
, etc
Para começar, importamos o vue dentro da primeira tag <script>
. Depois, iniciamos uma tag html com um id
. Por fim, realizamos a instancia de Vue passando o id
para o parametro el
. Tudo isso pode ser feito sem a instalação de qualquer dependencia.
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<p>{{ message }}</p>
</div>
<script>
new Vue({
el: "#app",
data: {
message: 'Ola, mundo Vue'
}
})
</script>
...
<div id="app" v-bind:title="message">
<p>Passe por aqui para ver a mensagem</p>
</div>
<script>
new Vue({
el: "#app",
data: {
message: "Ola, mundo Vue",
},
});
</script>
...
<div id="app" v-if="see">
<p>Voce só pode ver isso se 'see' for true</p>
</div>
<script>
new Vue({
el: "#app",
data: {
see: true,
},
});
</script>
...
<div id="app">
<ol>
<li v-for="(item, key) in items" :key="key">{{ item.text }}</li>
</ol>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
items: [{ text: "primeiro" }, { text: "segundo" }, { text: "terceiro" }],
},
});
</script>
-
Neste próximo exemplo estamos usando um botão para ouvir o evento
onClick
pelov-on:click
. Também poderiamos usar o@dblclick
para detectar o click duplo em um elemento. -
Quando esse evento acontecer, chamamos a função
invert
, pegamos a mensagem comthis.message
e a invertemos.
<div id="app">
<p>{{ message }}</p>
<button v-on:click="invert">Inverter string</button>
</div>
<script>
new Vue({
el: "#app",
data: {
message: "Ola, mundo Vue",
},
methods: {
invert() {
this.message = this.message.split("").reverse().join("");
},
},
});
</script>
Com v-model
conseguimos escutar o valor de inputValue
e atualizar o que aparece na tela dentro da tag p
automaticamente.
...
<div id="app">
<p>{{ inputValue }}</p>
<input v-model="inputValue" />
</div>
<script>
new Vue({
el: "#app",
data: {
inputValue: "valor default",
},
});
</script>
Instale o VUE na sua máquina de acordo com a documentação
Depois, crie o projeto com:
vue create <nome-do-projeto>
Em seguida, o VUE vai te perguntar algumas coisas para configurar e instalar as dependencias do projeto. Depois disso, entre na pasta e execute:
cd <nome-do-projeto> && yarn server
<textarea v-model="comment" id="comment"/>
watch: {
// sempre que o comentário mudar, essa função será executada
comment: function () {
console.log(this.comment)
}
},
Uma das particularidades do Vue é que os componentes de arquivo único possuem 3 partes (html, js e css), para muitos isso pode parecer um problema, já que aparentemente teremos muitas responsabilidades, porém, eles foram desenvolvidos assim a fim de mantê-los mais fáceis de realizar manutenção, já que todo o script e estilo são acoplados naquele componente.
Outro ponto importante, é que essa estrutura nos estimula a criar componentes menores por estarem todos juntos.
Para saber mais, recomendo a própria documentação que fala sobre separação de responsabilidades e o artigo Descomplicando os Single File Components do Vue.js, por Emanuel G de Souza