Propriedades Computadas
Exemplo Básico
As expressões no modelo de marcação são muito convenientes, porém estas estão destinadas às operações simples. Colocar muita lógica nos nossos modelos de marcação pode torná-los inchados e difíceis de manter. Por exemplo, se tivermos um objeto com um vetor encaixado:
js
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
E queremos exibir mensagens diferentes se o author
já tiver alguns livros ou não:
template
<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
Neste ponto, o modelo de marcação está ficando um pouco desarrumado. Nós temos que olhar neste por um segundo antes de percebermos que este realiza um cálculo dependendo da author.books
. Acima de tudo, provavelmente não queremos ser repetitivos ao incluir este cálculo no modelo de marcação mais de uma vez.
É por isto que para lógica complexa que inclui dados reativos, é recomendado usar uma propriedade computada. Eis o mesmo exemplo, refeito:
vue
<script setup>
import { reactive, computed } from 'vue'
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
// uma referência computada
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
</script>
<template>
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>
</template>
Experimentar na Zona de Testes
Eis que declaramos uma propriedade computada publishedBooksMessage
. A função computed()
espera uma função recuperada ser passada, e o valor retornado ser uma referência computada. Semelhante às referências normais, podemos acessar o resultado computado como publishedBooksMessage.value
. As referências computadas também são embrulhadas automaticamente nos modelos de marcação, assim podemos referenciá-las sem .value
nas expressões do modelo de marcação.
Uma propriedade computada rastreia automaticamente suas dependências reativas. A Vue está consciente de que a computação de publishedBooksMessage
depende da author.books
, então esta atualizará quaisquer vínculos que dependem da publishedBooksMessage
quando author.books
mudar.
Consultar também: Tipificando os Computados
Armazenamento de Consulta Imediata de Computado vs Métodos
Nós podemos ter reparado que podemos alcançar o mesmo resultado invocando um método na expressão:
template
<p>{{ calculateBooksMessage() }}</p>
js
// no componente
function calculateBooksMessage() {
return author.books.length > 0 ? 'Yes' : 'No'
}
No lugar duma propriedade computada, podemos definir a mesma função como um método. Para resultado final, as duas abordagens são de fato exatamente a mesma. No entanto, a diferença é que as propriedades computadas são armazenadas para consulta imediata baseada nas suas dependências reativas. Uma propriedade computada apenas reavaliará quando algumas das suas dependências reativas tiverem mudado. Isto significa que enquanto author.books
não tiver mudado, vários acessos ao publishedBooksMessage
retornarão imediatamente o resultado computado anteriormente sem precisar executar a função recuperadora novamente.
Isto também significa que a seguinte propriedade computada nunca atualizará, porque Date.now()
não é uma dependência reativa:
js
const now = computed(() => Date.now())
Em comparação, uma invocação de método sempre executará a função sempre que um reinterpretação acontecer.
Por que precisamos do armazenamento de consulta imediata? Imaginemos que temos uma propriedade computada dispendiosa list
, que exige percorrer um vetor enorme e fazer muitos cálculos. Depois podemos ter outras propriedades computadas que por sua vez dependem da list
. Sem o armazenamento de consulta imediata, estaríamos executando o recuperador da list
mais vezes do que necessário! Nos casos onde não queremos o armazenamento de consulta imediata, usamos uma chamada de método.
Propriedades Computadas Graváveis
As propriedades computadas são por padrão apenas recuperadoras. Se tentarmos atribuir um novo valor a uma propriedade computada, receberemos um aviso de execução. Nos casos raros onde precisamos duma propriedade computada "gravável", podemos criar uma fornecendo ambos um recuperador e um definidor:
vue
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed({
// recuperador
get() {
return firstName.value + ' ' + lastName.value
},
// definidor
set(newValue) {
// Nota: estamos usando a sintaxe de atribuição desestruturada.
[firstName.value, lastName.value] = newValue.split(' ')
}
})
</script>
Agora quando executarmos fullName.value = 'John Doe'
, o definidor será invocado e firstName
e lastName
serão atualizadas por consequência.
Boas Práticas
Os recuperadores não deveriam ter efeitos colaterais
É importante lembrar que as funções recuperadoras computadas apenas deveriam realizar computação pura e ser livres de efeitos colaterais. Por exemplo, não fazer requisições assíncronas ou alterar o DOM dentro dum recuperador computado! Pensemos duma propriedade computada como declarativamente descrevendo como derivar um valor baseado em outros valores - sua única responsabilidade deveria ser computar e retornar este valor. Mais tarde no guia discutiremos como realizamos efeitos colaterais em reação às mudanças de estado com os observadores.
Evitar alterar o valor computado
O valor retornado duma propriedade computada é o estado derivado. Consideremos esta como uma fotografia temporária - toda vez que o estado de origem mudar, uma nova fotografia é criada. Não faz sentido alterar uma fotografia, então um valor de retorno computado deveria ser tratado como destinada apenas a leitura e nunca deveria ser alterada - ao invés disto, atualizamos o estado de origem do qual este depende para acionar novos cálculos.