Vue.js: Propriedades Computadas
Última atualização: 2026-08-26
As propriedades computadas (computed) são propriedades especiais do Vue 3 que são recalculadas automaticamente com base em dados reativos. Seu principal valor está no armazenamento em cache — elas só são recalculadas quando os dados dependentes mudam; caso contrário, simplesmente retornam o valor anterior. Compreender as propriedades computadas é fundamental para escrever aplicativos Vue de alto desempenho.
No cerne das propriedades computadas estão três características fundamentais: rastreamento automático de dependências + armazenamento em cache dos resultados + reatividade. Esta aula vai ajudá-lo a dominar seus cinco casos de uso e a evitar suas três armadilhas.
1. O que você vai aprender
computed()Sintaxe básica e valores de retorno- Principais diferenças entre propriedades calculadas e métodos (armazenamento em cache)
- Propriedades calculadas bidirecionais com getter e setter
- Chamadas encadeadas a propriedades calculadas (calculadas dentro de outras propriedades calculadas)
- Diferentes usos de “computed” em modelos e métodos
- 3 armadilhas comuns (uso indevido, dependências circulares, problemas de desempenho)
2. Um problema de desempenho relacionado ao preço total do carrinho de compras
(1) Problema: 100 produtos são recalculados a cada clique
Alice criou o cálculo do total do carrinho no painel de administração do seu site de comércio eletrônico:
// ❌ The "Broken" Version: Use methods
function cartTotal(items) {
console.log('Calculating...') // Print on every call
return items.reduce((sum, item) => sum + item.price * item.quantity, 0)
}
<template>
<div>
<p>Total: ${{ cartTotal(items) }}</p>
<p>Tax: ${{ cartTotal(items) * 0.08 }}</p>
<p>Grand Total: ${{ cartTotal(items) * 1.08 }}</p>
<button @click="showDate = new Date()">Update Time</button>
</div>
</template>
O desempenho é péssimo:
- Carregamento da página: o cálculo é executado 1 vez ✅
- Calcular uma vez: 3 vezes (Total, Imposto, Total Geral) = 300 cálculos de itens
- O usuário clica em “Atualizar hora” (sem relação com os itens): 0 alterações, mas o cálculo ainda é executado 3 vezes = 300 cálculos de itens
A ferramenta de monitoramento de desempenho mostra:
“A função
cartTotalé chamada 5.000 vezes a cada carregamento da página. 100 itens × 5.000 = 500.000 cálculos item por item. Aplacação de 3 segundos.”
(2) Solução com computados do Vue: Armazenamento em cache + rastreamento de dependências
import { ref, computed } from 'vue'
const items = ref([
{ price: 100, quantity: 2 },
{ price: 50, quantity: 1 }
])
// ✅ computed:Rely solely on items,items If it hasn't changed, don't recalculate it.
const cartTotal = computed(() => {
console.log('Calculating...') // Only at items Print when changes occur
return items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
})
// computed Auto-Processing 3 For use in: Count only 1 time
const tax = computed(() => cartTotal.value * 0.08)
const grandTotal = computed(() => cartTotal.value * 1.08)
(3) Receita
Após mudar para “computed”:
- Chamadas de função: 5.000 → 100 (-98%)
- Tempo até a interação: 3 s → 80 ms (-97%)
- Travamento durante a rolagem: 5/s → 0 (-100%)
- Utilização da CPU: 80% → 5% (-94%)
3. Uso básico da função computed()
(1) Sintaxe padrão
import { ref, computed } from 'vue'
const count = ref(0)
// Basic Computational Properties
const doubleCount = computed(() => {
return count.value * 2
})
// Abbreviation
const doubleCount = computed(() => count.value * 2)
// Usage
console.log(doubleCount.value) // 0
count.value = 5
console.log(doubleCount.value) // 10
(2) Uso em modelos
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double: {{ doubleCount }}</p>
<button @click="count++">+1</button>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
</script>
No modelo, {{ doubleCount }} não é obrigatório .value (descompactado automaticamente).
(3) 5 Principais Características
graph TB
subgraph ComputedKey Features
A[Automatic Dependency Tracking]
B[Cache Results]
C[Responsive]
D[Lazy Evaluation]
E[Chainable calls]
end
style A fill:#42b883,color:#fff
style B fill:#42b883,color:#fff
style C fill:#42b883,color:#fff
style D fill:#42b883,color:#fff
style E fill:#42b883,color:#fff
| Recurso | Descrição |
|---|---|
| Rastreamento automático de dependências | Detecta automaticamente os dados reativos utilizados no corpo das funções |
| Resultados em cache | Acessos múltiplos contam como apenas 1 quando as dependências permanecem inalteradas |
| Responsivo | Recalcula automaticamente quando as dependências mudam |
| Avaliação preguiçosa | Não é avaliada a menos que seja acessada (economiza desempenho) |
| Encadeável | o valor da propriedade computada pode depender de outras propriedades computadas |
4. Computed vs. métodos: 5 diferenças principais
| Aspecto | calculado | métodos |
|---|---|---|
| Armazenamento em cache | ✅ Não há recálculo se as dependências permanecerem inalteradas | ❌ Recalcula a cada chamada |
| Responsivo | ✅ Rastreia dependências automaticamente | ❌ Não rastreia (requer a passagem manual de parâmetros) |
| Acesso ao modelo | {{ doubleCount }} |
{{ doubleCount() }} |
| Parâmetros | ❌ Não suportado | ✅ Aceita qualquer parâmetro |
| Casos de uso | Valores derivados simples | Lógica complexa, tratamento de eventos |
(4) 5 cenários à sua escolha
| Cenário | Usando valores calculados | Usando métodos |
|---|---|---|
| Duplique o número exibido | ✅ | ❌ |
| Calcular o valor total do carrinho | ✅ | ❌ |
| Processar clique no botão | ❌ | ✅ |
| Enviar solicitação de API | ❌ | ✅ |
| Formatação de data (sem dependências) | ❌ | ✅ |
| Lista de filtros (depende dos dados) | ✅ | ❌ |
| Validação do formulário | ❌ | ✅ |
5. Getter/Setter: Propriedades calculadas bidirecionais
(1) Por padrão, existe apenas um getter
const firstName = ref('Alice')
const lastName = ref('Smith')
// There is only one getter
const fullName = computed(() => `${firstName.value} ${lastName.value}`)
console.log(fullName.value) // Alice Smith
// fullName.value = 'Bob Lee' // ❌ Warning:Calculated properties are read-only.
(2) Getters e setters completos
const firstName = ref('Alice')
const lastName = ref('Smith')
const fullName = computed({
// Read:Put it together
get() {
return `${firstName.value} ${lastName.value}`
},
// Write:Unpack
set(newValue) {
const parts = newValue.split(' ')
firstName.value = parts[0]
lastName.value = parts[1] || ''
}
})
// ✅ Read and write access is now available
fullName.value = 'Bob Lee'
console.log(firstName.value) // Bob
console.log(lastName.value) // Lee
(3) Vinculação bidirecional em modelos
<template>
<div>
<input v-model="fullName">
<p>First: {{ firstName }}</p>
<p>Last: {{ lastName }}</p>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('Alice')
const lastName = ref('Smith')
const fullName = computed({
get: () => `${firstName.value} ${lastName.value}`,
set: (val) => {
const parts = val.split(' ')
firstName.value = parts[0]
lastName.value = parts[1] || ''
}
})
</script>
6. Chamadas encadeadas para propriedades calculadas
(1) Cálculos aninhados
const items = ref([
{ price: 100, quantity: 2 },
{ price: 50, quantity: 3 }
])
// First Floor:Total Original Price
const subtotal = computed(() =>
items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
)
// Second Floor: Tax (Based on subtotal)
const tax = computed(() => subtotal.value * 0.08)
// Third Floor: Discount (Based on subtotal)
const discount = computed(() => subtotal.value > 200 ? 20 : 0)
// Fourth Floor:Final Total Price
const total = computed(() => subtotal.value + tax.value - discount.value)
console.log(total.value) // 350 * 1.08 - 20 = 358
(2) Mecanismo de cache com cálculo em cadeia
graph TB
A[items change] --> B[subtotal Recalculate]
B --> C[tax Recalculate]
B --> D[discount Recalculate]
C --> E[total Recalculate]
D --> E
style A fill:#42b883
style B fill:#42b883
style E fill:#42b883
Apenas os valores calculados que dependem da cadeia serão recalculados; os que não forem utilizados não serão recalculados.
7. Exemplo completo: Preço total de um carrinho de compras em um site de comércio eletrônico
▶ Exemplo: 1. Cálculo básico
<template>
<div>
<p>Subtotal: ${{ subtotal }}</p>
<p>Tax (8%): ${{ tax }}</p>
<p>Discount: -${{ discount }}</p>
<p><strong>Total: ${{ total }}</strong></p>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const items = ref([
{ name: 'iPhone', price: 999, quantity: 1 },
{ name: 'Case', price: 50, quantity: 2 }
])
const subtotal = computed(() =>
items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
)
const tax = computed(() => subtotal.value * 0.08)
const discount = computed(() => subtotal.value > 1000 ? 50 : 0)
const total = computed(() => subtotal.value + tax.value - discount.value)
</script>
▶ Exemplo: 2. getters + setters
<template>
<div>
<input v-model="fullName" placeholder="First Last">
<p>First: {{ firstName }}</p>
<p>Last: {{ lastName }}</p>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('Alice')
const lastName = ref('Smith')
const fullName = computed({
get: () => `${firstName.value} ${lastName.value}`,
set: (val) => {
const parts = val.split(' ')
firstName.value = parts[0] || ''
lastName.value = parts[1] || ''
}
})
</script>
▶ Exemplo: 3. Chamadas em cadeia calculadas
import { ref, computed } from 'vue'
const score = ref(85)
// First Floor:Base Score
const baseScore = computed(() => score.value)
// Second Floor:Bonus Points(Base Score × Difficulty Level)
const difficultyBonus = computed(() => {
if (baseScore.value >= 90) return 10
if (baseScore.value >= 80) return 5
return 0
})
// Third Floor:Level
const grade = computed(() => {
const total = baseScore.value + difficultyBonus.value
if (total >= 95) return 'A+'
if (total >= 90) return 'A'
if (total >= 80) return 'B'
return 'C'
})
▶ Exemplo: 4. Comparação entre computados e métodos
// ❌ methods:Recalculate on every call
function getTotal() {
console.log('Calculated!') // If used multiple times in the template, it will be printed multiple times.
return items.value.reduce((sum, i) => sum + i.price * i.quantity, 0)
}
// ✅ computed: Count only 1 time
const total = computed(() => {
console.log('Calculated!') // Print Only 1 time
return items.value.reduce((sum, i) => sum + i.price * i.quantity, 0)
})
▶ Exemplo: 5. Cinco cenários de comparação de desempenho
| Cena | Número de métodos chamados | Número de chamadas calculadas |
|---|---|---|
| Usado 1 vez no modelo | 1 | 1 |
| Usado 3 vezes no modelo | 3 | 1 |
| Usado 10 vezes no modelo | 10 | 1 |
| O componente pai é atualizado, mas os itens permanecem inalterados | Recuperado | Não recalculado |
| Alterações nas dependências | Revogação | Recálculo |
▶ Exemplo: 6. 5 erros comuns
| Erro | Sintoma | Solução |
|---|---|---|
| Substituir métodos por expressões calculadas | Baixo desempenho com uso repetido | Mudar para expressões calculadas |
Passagem incorreta de parâmetros para computed |
Erro | computed não aceita parâmetros; use methods em vez disso |
| setter: Escreva o seu próprio | Loop infinito | setter: Modifique a dependência; não use fullName.value = ... |
| Dependência circular A→B→A | Loop infinito | Remova uma das dependências |
| Lógica complexa escrita em propriedades calculadas | Difícil de depurar | Extraia para um método; faça com que a propriedade calculada chame o método |
❓ Perguntas Frequentes
P: O que devo usar —
computedoumethods? R: Usecomputedsempre que possível (armazenamento em cache + rastreamento automático). Usemethodsapenas nas seguintes situações: (1) quando precisar passar parâmetros; (2) quando não depender de dados reativos; (3) para manipuladores de eventos (@click, etc.).
P: O
computedpode aceitar parâmetros? R: Não. Ocomputedsó pode ter 0 parâmetros. Se você precisar passar parâmetros, use omethodsem vez disso:getDouble(n) { return n * 2 }, ou faça com que ocomputedretorne uma função:computed(() => (n) => n * 2).
P: É possível acessar
computedfora desetup? R: Sim.computedretorna um objetoref, que pode ser passado para outros componentes ou funções. No entanto, para manter a reatividade, recomenda-se usarcomputedcomo uma “referência derivada”.
P: Qual é a diferença entre
computedewatch? R:computedé um “valor derivado” (cálculo de um novo valor com base em dados), enquantowatché um “observador” (execução de efeitos colaterais quando os dados mudam).computedé adequado para cálculos puros, enquantowatché adequado para fazer solicitações, definir estado e assim por diante.
P: Por que o
computedtem melhor desempenho do que omethods? R: Armazenamento em cache. Omethodsexecuta a função a cada chamada, enquanto ocomputedsó é executado quando suas dependências mudam. No modelo, usar ocomputedtrês vezes resulta em apenas um cálculo; usar omethodsresulta em três cálculos.
P: Como faço para escrever um setter de forma que ele não entre em um loop infinito? R: No setter, atualize apenas as dependências do computed (ref); não atribua um valor diretamente ao próprio computed. Por exemplo, o setter para
fullNamedeve atualizarfirstNameelastName, e nãofullName.value = ....
P: O
computedpode ser assíncrono? R: Não. Ocomputedé síncrono; usewatchouwatchEffectpara operações assíncronas. Se você precisar de “propriedades calculadas assíncronas”, use a combinação dedata() { return { result: null } }ewatch + onMounted.
📖 Resumo
computedé uma “referência derivada” que se recalcula automaticamente com base em dados reativos. Possui cinco características principais: rastreamento automático, armazenamento em cache, reatividade, avaliação preguiçosa e encadeabilidade.{{ doubleCount }}no modelo não requer .value (desempacotamento automático);doubleCount.valueem JS- computed vs métodos: os computed armazenam em cache (desempenho), enquanto os métodos não armazenam em cache, mas aceitam parâmetros
- Propriedades computadas bidirecionais com getter/setter: legíveis e graváveis; o setter atualiza as dependências, mas não se atualiza a si mesmo
- Chamadas em cadeia em propriedades calculadas: uma propriedade calculada pode depender de outras propriedades calculadas; propriedades calculadas não utilizadas não são recalculadas.
- 3 armadilhas: dependências circulares, uso indevido de métodos e lógica complexa que dificulta a depuração
- Desempenho: A propriedade
computedé usada em três lugares no modelo, mas é avaliada apenas uma vez, enquantomethodsé avaliada três vezes.
📝 Exercícios
-
Questões básicas (Dificuldade: ⭐)
Escreva uma propriedade computada
wordCountque conte o número de palavras em um trecho de texto (usandosplitpara dividir o texto por espaços).Dados:
const text = ref('Hello Vue 3 from Alice')Deveria exibir 4. -
Problemas avançados (Dificuldade: ⭐⭐)
Escreva um cálculo do total do carrinho de compras que inclua três propriedades calculadas:
subtotal: A soma do preço e da quantidade de todos os itensdiscount: Economize 10 em pedidos de 100 ou mais; economize 30 em pedidos de 200 ou maistotal: subtotal - desconto- 3 itens: iPhone $999 × 1, capa $50 × 2, carregador $30 × 1
-
Problema de desafio (Dificuldade: ⭐⭐⭐)
Implementar um “sistema completo de cálculo do total do carrinho de compras”:
- 5 produtos, cada um com nome, preço e quantidade
- subtotal / imposto (8%) / desconto (20 de desconto para compras de 200 ou mais) / total — 4 valores calculados
- Use getters e setters para a propriedade calculada
fullName; no setter, atualizefirstNameelastNamecom base na entrada. - Testar o rastreamento de dependências para 5 propriedades calculadas (quais são recalculadas após a modificação de qualquer produto)
- Use o Mermaid para desenhar um gráfico de dependências para propriedades calculadas