Simplifiez vos composants Vue avec la Composition API

Clément Rivaille
Lonestone
Published in
6 min readNov 10, 2020

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éfaut any. 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 de this !

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 utilise reactive.

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.

--

--