Simplifiez vos composants Vue avec la Composition API
La Composition API est la nouvelle syntaxe de Vue.js pour la création de composants, introduite par Vue 3. Son objectif est de délaisser la déclaration par classe pour s’orienter vers du fonctionnel. La composition API se veut ainsi plus légère, davantage réutilisable, mieux typée, et permet de regrouper les logiques par “métier”.
Cet article a pour but d’initier rapidement à la Composition API. Pour plus d’informations, vous pouvez consulter la présentation complète de la Composition API par Vue.
Pourquoi changer ce qui marche déjà bien ?
Pour rappel, avec « l’ancienne » syntaxe (toujours compatible avec Vue 3 néanmoins), on déclare les données d’un composant dans plusieurs de ses propriétés :
- props liste les données d’entrées du composant
- data renseigne les données initiales
- computed renseigne des données calculées et mises à jour dynamiquement à partir des variables dans props et data
- methods liste les fonctions pouvant être appelées depuis le template
À ceci s’ajoutent des fonctions liées au cycle de vie du composant (onMounted, onDestroyed, etc). Avec cette syntaxe, pour accéder aux données du composant à l’intérieur de ses logiques, il faut passer par this
.
Principaux soucis de cette syntaxe
- L’utilisation de
this
: C'est une valeur très volatile en JavaScript ou TypeScript ! Il change avec le scope, mais différemment selon la façon dont on déclare la fonction. En Vue, il a des propriétés un peu magiques, qui n'aident pas à sa compréhension, et favorisent des erreurs d'inattention. - Typage bancal : Ceci est lié au premier point. À moins de typer explicitement
this
(et encore !), il vaut par défautany
. Le fait d'avoir la donnée séparée en plein d'endroits ne facilite pas non plus la mise en place d'un modèle de données solide. - Partage de logique : Si l’on souhaite que plusieurs composants aient des données ou de la logique en commun, il faut passer par des mixins. Quiconque s’y est frotté sait à quel point cette solution est délicate à manipuler. Une mixin fonctionne plus ou moins comme un héritage de classe : elle va modifier le composant, exécuter de la logique supplémentaire, sans que l’on ait une vision précise de ses impacts. Si on n’y prend pas garde, une mixin peut surcharger une partie de la logique du composant, et écraser ce qui y est déjà en place. Et ne parlons même pas du cas où l’on souhaite en utiliser plusieurs !
- Structure du code : Sur le papier, diviser les membres d’un composant par rôle paraît une bonne idée. Ici la donnée, là les fonctions, là les données calculées… Mais dès qu’un composant doit gérer plusieurs problématiques, la lecture est bien plus fastidieuse ! Une variable dans data peut dépendre d’une fonction décrite dans methods, mais des dizaines de lignes de codes les séparent ! La logique se retrouve finalement dispersée, et mélangée de manière inconsistante, car elle est triée par sémantique plutôt que par logique. Vue illustre bien ce problème dans sa documentation. Et encore une fois, l’utilisation de
this
rend fastidieux la séparation en plusieurs fonctions.
La Composition API répond à ces problèmes, en simplifiant l’écriture des composants et en proposant une approche fonctionnelle plutôt qu’orientée objet.
Fondamentaux de la Composition API
Avec la composition API, l’ensemble de la logique d’un composant s’écrit dans une fonction setup
. Cette fonction retourne un objet dont les clés fournissent des données et méthodes qui pourront être utilisées depuis le template.
<template>
<div class="content">{{ greetings }} {{ name }}</div>
</template><script>
export default {
name: "hello-world",
props: {
name: String
},
setup(props, context) {
return {
greetings: "Hello"
}
}
}
</script>
La fonction setup a deux arguments :
- props : L’ensemble des props passées au composant, typées de la même manière qu’elles ont été déclarées
- context : Accès à certaines propriétés et méthodes de l’instance du composant. C’est notamment via celui-ci que l’on peut appeler la méthode
emit
pour émettre un événement. En quelque sorte il s'agit du remplaçant dethis
!
Cependant, tel quel, la fonction setup
ne va pas suffire ! En effet, si l'on se contente de retourner directement des variables, celles-ci seront considérées comme des valeurs statiques. Ce que l'on veut généralement, c'est des données dynamiques qui se mettent à jour dans le template au moment où elles sont modifiées. Pour cela, on va faire appel aux fonctions ref
et reactive
.
Ref et Reactive
C’est ici que les choses deviennent un peu complexes ! Pour faire court, ref
et reactive
ont la même finalité : initialiser de la donnée dynamique ("réactive"), qui se mettra à jour dans le template et plus généralement au sein de l'application toute entière. Elles s'initialisent avec une valeur, et retournent un proxy de variable réactif.
Exemple avec reactive
:
<script>
import { reactive } from 'vue' export default {
name: 'counter-btn',
setup() {
const state = reactive({
count: 0
})
function increment() {
state.count++
}
return {
state,
increment
}
}
}
</script><template>
<div>
Value: {{ state.count }}
<button @click="increment">Increment</button>
</div>
</template>
Quand utiliser ref
et quand utiliser reactive
? Pour simplifier, la règle est :
Pour les valeurs natives (number, string, boolean…), on utilise
ref
, pour les objets et tableaux, on utilisereactive
.
La version un peu plus longue, c’est que Vue a besoin d’un objet pour faire fonctionner la réactivité. reactive
retourne ainsi un objet "réactif", avec les mêmes propriétés que celles qu'on lui passe en entrée. ref
, en revanche, ne retourne pas une valeur, mais un objet proxy. Pour accéder à la valeur et la modifier, il faut passer par la propriété value
.
const count = ref(0)
function increment() {
count.value++
}
const double = computed(() => count.value * 2)
return {
count,
double,
increment
}
Note : depuis le template, en revanche, il n’y a pas besoin de passer par .value, {{ count }}
suffit !
Notez au passage l’utilisation de computed
, une fonction de Vue qui retourne une valeur calculée à partir de données réactives, et la met à jour automatiquement.
Il existe d’autres fonctions utilitaires fournies par la Composition API. La liste est détaillée dans la documentation de l’API. L’essentiel à retenir est que l’on manipule principalement des proxy réactifs de nos valeurs, créés à partir de ref
ou reactive
.
Conseil : si vous ne savez pas lequel des deux utiliser, vous pouvez partir avec reactive
par défaut sans trop vous tromper.
Découpage de la logique
Maintenant que toute la logique est regroupée dans une unique fonction setup
, il serait facile de tout y coder pêle-mêle et se retrouver avec des logiques de centaines de lignes ! Ce n'est pas le but de la Composition API. L'intérêt de celle-ci, c'est qu'elle permet de découper la logique par sujets*,* et faciliter la réutilisation.
Pour cela, on utilise simplement des fonctions ! Voici par exemple un incrémenteur générique un peu plus complexe que celui d’au-dessus (permettant de compter par 2, ou 3, etc).
import { reactive, computed } from "vue"// On utilise la nomenclature "useXXX" pour nommer les fonctions de rendu réactif ("hooks"), inspiré de React.js
export function useIncrement(step = 1) {
const state = reactive({
count: 0,
value: computed(() => state.count * step)
})
function increment() {
state.count++
} return {
value: state.value,
increment
}
}
Utilisation dans un composant :
import { useIncrement } from './increment'export default {
name: 'counter-btn',
props: {
step: Number
},
setup(props) {
const { value, increment } = useIncrement(props.step)
return {
value,
increment
}
}
}
Notez que les props sont elles-mêmes des données réactives (donc value
se mettra bien à jour si step
change).
Commencer à utiliser la Composition API
Vue 3 est officiellement sorti le 18 septembre 2020. Mais à ce jour, en octobre 2020, il est peut-être encore un peu tôt pour l’utiliser : le tooling (librairies complémentaires, extensions d’IDE…) n’est pas tout à fait prêt, et il faudra patienter quelques temps pour qu’émergent les documentations solides et l’aide en ligne.
Mais fort heureusement, il est déjà possible d’utiliser la Composition API sous Vue 2 ! En installant le package @vue/composition-api, on accède à la méthode setup
ainsi que toutes les fonctions utilitaires.
npm install @vue/composition-api
Dans un fichier JS ou TS :
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'Vue.use(VueCompositionAPI)
Même si le gain de performance est moindre par apport à Vue 3, on conserve tous les autres avantages mentionnés. Cela permet aussi une bien meilleure intégration avec TypeScript !
La Composition API accélère nettement le développement d’application Vue, et offre une structure très agréable à utiliser. Si vous êtes développeur Vue, vous gagnerez à l’essayer (et l’adopter) au plus tôt !
Si cet article vous paraît intéressant, mettez des claps, partagez et commentez ! Je répondrai avec plaisir à vos questions. Je développe des applications Vue chez Lonestone, contactez-moi si vous aimeriez travailler avec nous.