Boas práticas no Vue

Aprenda boas práticas no Vue para componentes menores, props tipadas, script setup, Pinia e keys estáveis — torne seu código previsível e mais fácil de manter.

Avatar de Gabriel
Gabriel
Boas práticas no Vue

Você já sabe montar um componente Vue. A pergunta é se ele vai continuar fazendo sentido daqui a três meses, quando outra pessoa (ou você mesmo, sem memória) abrir o arquivo. Boas práticas no Vue não são regra de estilo — são o que separa um componente que você entende de relance de um que precisa ser depurado toda vez.

Imagem de abertura que traduz visualmente a ideia de código Vue bem organizado — componentes pequenos, encaixados e previsíveis — sem cair no clichê de tela de código.
Imagem de abertura que traduz visualmente a ideia de código Vue bem organizado — componentes pequenos, encaixados e previsíveis — sem cair no clichê de tela de código.

script setup não é açúcar, é o padrão

Se você ainda escreve setup() retornando um objeto, pare. <script setup> é o default moderno: menos boilerplate, melhor inferência de tipo, e tudo declarado no topo já está exposto ao template. Composition API com script setup deixa a lógica agrupada por assunto, não espalhada entre data, methods e computed como no Options API. Você lê de cima a baixo e entende o que o componente faz.

Componente grande é bug esperando acontecer

Um SFC de 400 linhas com seis responsabilidades é impossível de testar e horrível de reusar. Quebre. Se um trecho do template tem estado próprio e nome próprio, é um componente. A regra prática: se você precisa rolar a tela pra ver o <script> inteiro, provavelmente já passou do ponto. Componente pequeno também torna a reatividade previsível — menos estado num lugar só, menos efeito colateral surpresa.

Props tipadas e emits explícitos

Props sem tipo são contrato quebrado esperando acontecer. Use a assinatura genérica:

const props = defineProps<{ userId: number; active?: boolean }>()
const emit = defineEmits<{ (e: 'update', value: string): void }>()

Agora o editor te avisa quando alguém passa userId como string, e o emit é rastreável — nada de eventos fantasma que ninguém sabe de onde vêm. Props são read-only: mutar prop dentro do filho é o clássico bug que some e volta. Emitiu, o pai decide.

computed no lugar de watcher (quase sempre)

Esse é o erro mais comum de quem vem de outros frameworks. Precisa de um valor derivado de outro? computed. Ele é cacheado, declarativo, e reavalia sozinho quando a dependência muda:

const fullName = computed(() => `${first.value} ${last.value}`)

Watcher é para efeito colateral — disparar um fetch, sincronizar com localStorage, logar. Se o seu watch termina atribuindo a outra variável reativa, quase sempre era um computed disfarçado. Watcher demais é sinal de estado que devia ser derivado.

Pinia para estado global, e só

Estado que dois componentes distantes compartilham vai pra store. Pinia é o padrão hoje: tipado, sem mutations, com state/getters/actions limpos. Mas cuidado com o exagero oposto — nem tudo é global. Estado que só um componente e seus filhos usam fica local ou desce via props. Store lotada de coisa que era local vira um balde de estado que ninguém entende. Global é para o que é global de verdade: usuário logado, tema, carrinho.

key estável em v-for não é detalhe

:key diz ao Vue qual item é qual entre renders. Usar o índice do array como key é pedir bug: reordenou, filtrou ou removeu um item e o Vue reaproveita o nó errado — input com valor trocado, componente com estado grudado no lugar errado. Use um id estável e único do próprio dado:

<li v-for="item in items" :key="item.id">{{ item.name }}</li>

Índice só serve pra lista estática que nunca muda de ordem. Na dúvida, id.

Nenhuma dessas coisas é difícil. São hábitos. O componente que segue todos eles não é mais inteligente — é só mais chato de errar, e é exatamente isso que você quer num código que vai durar.

Gostou do artigo?

Compartilhe com seus amigos e ajude a espalhar conhecimento!