Propriétés calculées
Exemple basique
Les expressions dans le template sont pratiques, mais elles sont destinées à des opérations simples. Mettre trop de logique dans vos templates peut les encombrer et les rendre difficiles à maintenir. Par exemple, si nous avons un objet avec un tableau imbriqué :
js
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
Et que nous voulons afficher des messages différents selon que author
contiennent déjà ou non des livres :
template
<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
A ce stade, le template devient un peu chargé. Nous devons bien l'examiner avant de réaliser qu'il effectue une opération dépendante de author.books
. Plus important encore, nous ne voulons sûrement pas nous répéter si nous avons besoin de cette opération dans le template plus d'une fois.
C'est pourquoi pour des logiques complexes incluant des données réactives, il est recommandé d'utiliser une propriété calculée. Voici le même exemple, refactorisé :
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'
]
})
// a computed ref
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
</script>
<template>
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>
</template>
Ici nous avons déclaré une propriété calculée publishedBooksMessage
. La fonction computed()
prend une fonction accesseur en argument, et la valeur retournée est une ref calculée. De la même manière que pour les refs classiques, vous pouvez accéder au résultat calculé grâce à publishedBooksMessage.value
. Les refs calculées sont automatiquement déballées dans les templates de manière à ce que vous puissiez y faire référence sans .value
dans les expressions au sein du template.
Une propriété calculée traque automatiquement ses dépendances réactives. Vue sait que le calcul de publishedBooksMessage
dépend de author.books
, donc il va mettre à jour les liaisons dépendantes de publishedBooksMessage
lorsque author.books
change.
Voir aussi : Typer les propriétés calculées
Propriétés calculées mises en cache vs.. les méthodes
Vous avez peut-être remarqué que nous pouvons obtenir le même résultat en invoquant une méthode dans l'expression :
template
<p>{{ calculateBooksMessage() }}</p>
js
// dans le composant
function calculateBooksMessage() {
return author.books.length > 0 ? 'Yes' : 'No'
}
À la place d'une propriété calculée, nous pouvons définir la même fonction comme une méthode. Les deux approches mènent au même résultat final. Cependant, la différence est que les propriétés calculées sont mises en cache en fonction de leurs dépendances réactives. Une propriété calculée ne sera réévaluée que lorsque l'une de ses dépendances réactives aura changé. Cela signifie que tant que author.books
n'a pas changé, les accès multiples à publishedBooksMessage
vont immédiatement retourner le résultat calculé précédent sans avoir à réexécuter la fonction accesseur.
Cela signifie également que la propriété calculée suivante ne sera jamais mise à jour, car Date.now()
n'est pas une dépendance réactive :
js
const now = computed(() => Date.now())
En comparaison, l'invocation d'une méthode va toujours exécuter la fonction, à chaque nouveau rendu.
Pourquoi avons nous besoin de la mise en cache ? Imaginons que nous ayons une propriété calculée conséquente list
, qui nécessite de boucler à travers un important tableau et de réaliser de nombreuses opérations. Nous pourrions également avoir d'autres propriétés calculées dépendantes à leur tour de list
. Sans mise en cache, nous exécuterions les accesseurs de list
bien plus de fois que nécessaire ! Dans les cas où vous ne voulez pas de mise en cache, vous pouvez utiliser l'appel à une méthode.
Propriétés calculées modifiables
Par défaut, les propriétés calculées ne sont soumises qu'aux accesseurs. Si vous essayez d'assigner une nouvelle valeur à une propriété calculée, vous aurez un avertissement au moment de l'exécution. Dans les rares cas où vous avez besoin d'une propriété calculée "modifiable", vous pouvez en créer une en lui fournissant à la fois un accesseur et un mutateur :
vue
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed({
// accesseur
get() {
return firstName.value + ' ' + lastName.value
},
// mutateur
set(newValue) {
// Note : nous utilisons ici la syntaxe d'assignation par déstructuration
;[firstName.value, lastName.value] = newValue.split(' ')
}
})
</script>
Désormais lorsque vous allez exécuter fullName.value = 'John Doe'
, le mutateur sera invoqué et firstName
et lastName
seront mis à jour en conséquence.
Bonnes Pratiques
Les accesseurs ne doivent pas entraîner d'effets secondaires
Il est important de se rappeler que les fonctions accesseurs de propriétés calculées doivent seulement réaliser des opérations pures et ne pas entraîner d'effets secondaires. Par exemple, ne faites pas de requêtes asynchrones ou ne mutez pas le DOM à l'intérieur d'un accesseur calculé ! Pensez à une propriété calculée comme une description déclarative de la manière d'obtenir une valeur selon d'autres valeurs - sa seule responsabilité devrait être de calculer et de retourner cette valeur. Plus loin dans le guide nous traiterons de la manière d'effectuer des effets secondaires en réaction à des changements de l'état avec les observateurs.
Évitez de modifier les valeurs calculées
La valeur retournée par une propriété calculée est un état dérivé. Pensez-y comme un snapshot temporaire - chaque fois que l'état de base change, un nouveau snapshot est créé. Il n'est pas logique de modifier un snapshot, donc une valeur calculée retournée ne devrait être traitée qu'en lecture seule et ne pas être modifiée - à la place, modifiez l'état de base dont elle dépend afin d'engendrer de nouveaux calculs.