4e étageV VuePièce 6/7Avancé

Les composables

Extraire et réutiliser de la logique réactive entre plusieurs composants avec des fonctions useXxx.

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

src/composables/usePortions.js
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

src/components/Convives.vue
<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ègleDétail
Le nom commence par useusePortions, useMouse... en camelCase.
On renvoie un objet ordinaire contenant des refsLe 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.

Place tes composables dans un dossier 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 :

src/composables/useMouse.js
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>
Comme les hooks, un composable qui en utilise doit être appelé directement dans <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 useXxx qui encapsule une logique réactive réutilisable.
  • Il peut utiliser ref, computed, watch et 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
Lignes de code · fiches rédigées à partir des documentations officielles, sources citées en bas de chaque page.