Les composables
Ce que tu vas apprendre
- Ce qu'est un composable et pourquoi en écrire.
- Extraire une logique réactive dans une fonction
useXxx. - Respecter les conventions : nom, valeur de retour, état propre à chaque appel.
Le problème : copier-coller de logique
Imagine que deux composants ont besoin d'un compteur de portions, avec les mêmes boutons et le même calcul. Tu pourrais recopier le code dans les deux fichiers. Mais au premier correctif, tu devrais penser à modifier les deux.
Un composable règle ce problème : c'est une fonction qui utilise l'API de Vue (ref, computed, onMounted...) pour encapsuler une logique avec un état, et qui la rend réutilisable.
Écrire un composable
import { ref, computed } from 'vue'
export function usePortions(depart = 4) {
const portions = ref(depart)
const estGrandeTablee = computed(() => portions.value > 8)
function ajouter() {
portions.value++
}
function retirer() {
if (portions.value > 1) portions.value--
}
return { portions, estGrandeTablee, ajouter, retirer }
}
C'est une fonction ordinaire, dans un fichier .js ou .ts. Elle déclare un état, des valeurs calculées et des fonctions, puis les renvoie.
L'utiliser dans un composant
<script setup>
import { usePortions } from '../composables/usePortions.js'
const { portions, estGrandeTablee, ajouter, retirer } = usePortions(6)
</script>
<template>
<button @click="retirer">-</button>
{{ portions }} personnes
<button @click="ajouter">+</button>
<p v-if="estGrandeTablee">Prévois une grande table.</p>
</template>
Le composant récupère exactement ce dont il a besoin. Un deuxième composant peut appeler usePortions() de la même façon.
Les conventions
La documentation fixe deux règles simples :
| Règle | Détail |
|---|---|
Le nom commence par use | usePortions, useMouse... en camelCase. |
| On renvoie un objet ordinaire contenant des refs | Le composant peut le déstructurer sans perdre la réactivité. |
C'est pour cette raison qu'on renvoie { portions, ajouter } et non un objet reactive() : déstructurer un objet réactif détache ses propriétés.
src/composables/. Ce n'est pas une obligation de Vue, mais c'est un usage courant qui rend le projet lisible.Chaque appel a son propre état
Deux composants qui appellent usePortions() ne partagent pas leur compteur. Chaque appel de la fonction crée de nouveaux ref, indépendants des autres.
Si tu veux partager un état entre composants, un composable ne suffit pas tel quel. Il existe pour cela une bibliothèque dédiée, Pinia, que l'outil de création de projet propose d'installer. Ce n'est pas l'objet de ce chapitre.
Un composable avec le cycle de vie
Un composable peut aussi utiliser les hooks du chapitre précédent. Il nettoie alors lui-même ce qu'il a branché. C'est l'exemple de la documentation, qui suit la position de la souris :
import { ref, onMounted, onUnmounted } from 'vue'
export function useMouse() {
const x = ref(0)
const y = ref(0)
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
return { x, y }
}
Le composant qui l'utilise n'a rien à savoir de l'écouteur :
<script setup>
import { useMouse } from '../composables/useMouse.js'
const { x, y } = useMouse()
</script>
<template>
<p>Souris en {{ x }}, {{ y }}</p>
</template>
<script setup>, pas plus tard dans un setTimeout.Quand créer un composable ?
Pas dès la première ligne. Écris d'abord la logique dans le composant. Extrais-la quand tu la retrouves dans un second composant, ou quand le composant devient trop long pour être lu d'un coup.
Un bon composable a un nom qui dit ce qu'il fait et une courte liste de choses qu'il renvoie.
À retenir
- Un composable est une fonction
useXxxqui encapsule une logique réactive réutilisable. - Il peut utiliser
ref,computed,watchet les hooks de cycle de vie. - Il renvoie un objet ordinaire de refs, que le composant déstructure sans perdre la réactivité.
- Chaque appel crée un état indépendant.
- On extrait un composable quand la logique est répétée ou devient trop longue, pas avant.
Pour aller plus loin
Sources officielles
Ensuite
- Projet
- Lignes de code
- Niveau
- 4e étage
- Appartement
- Vue
- Pièce
- 6/7
- Plan n°
- vue/06.composables