Comprendre le comportement des composants Vue.js
Séance 5 — 25 février 2026
Flèches pour naviguer
Comprendre quand un composant naît, vit et meurt
Rappel des propriétés calculées avec mise en cache
Réagir aux changements de données avec watch()
💡 Pour le projet Pokédex
Ces concepts sont essentiels : onMounted pour charger les Pokémon, computed pour filtrer la liste, et watch pour réagir à la recherche.
Un composant Vue passe par plusieurs étapes : création, montage dans le DOM, mises à jour, et destruction.
Vue nous permet d'exécuter du code à chaque étape grâce aux hooks de cycle de vie.
💡 Analogie
Comme un être vivant : naissance → vie → mort. À chaque étape, on peut intervenir.
Les 2 hooks les plus utilisés
onMounted()
— Composant prêt dans le DOM
onUnmounted()
— Composant supprimé du DOM
setup()
Le script s'exécute
onBeforeMount
Avant l'insertion dans le DOM
onMounted
Le composant est dans le DOM ✅
onBeforeUpdate
Avant une mise à jour
onUpdated
Après une mise à jour
onBeforeUnmount
Avant la suppression
onUnmounted
Le composant est détruit ✅
<script setup> import { ref, onMounted } from 'vue' const users = ref([]) const loading = ref(true) onMounted(async () => { // Le composant est dans le DOM // Idéal pour charger des données const response = await fetch('/api/users') users.value = await response.json() loading.value = false }) </script> <template> <p v-if="loading">Chargement...</p> <ul v-else> <li v-for="user in users"> {{ user.name }} </li> </ul> </template>
🌐 Charger des données
Appeler une API pour récupérer des données au chargement
📚 Initialiser une librairie
Carte, graphique, éditeur qui ont besoin du DOM
👂 Ajouter un écouteur
Écouter le scroll, le resize, les touches clavier
🎯 Accéder au DOM
Lire des dimensions, mettre le focus sur un input
⚠️ Le DOM n'existe PAS dans setup()
Il faut attendre onMounted pour accéder aux éléments HTML
<script setup> import { ref, onMounted, onUnmounted } from 'vue' const scrollY = ref(0) function handleScroll() { scrollY.value = window.scrollY } // Ajouter l'écouteur onMounted(() => { window.addEventListener( 'scroll', handleScroll ) }) // Supprimer l'écouteur onUnmounted(() => { window.removeEventListener( 'scroll', handleScroll ) }) </script> <template> <p>Scroll : {{ scrollY }}px</p> </template>
Quand un composant est supprimé du DOM (navigation, v-if),
il faut nettoyer ce qu'on a mis en place.
🧠 Fuites mémoire
Les écouteurs non supprimés restent actifs en arrière-plan
⚡ Performances
Chaque listener inutile consomme des ressources
🐛 Bugs
Du code qui tourne sur un composant qui n'existe plus
💡 Règle d'or
Chaque addEventListener dans onMounted doit avoir son removeEventListener dans onUnmounted
// Recalculé à chaque rendu ❌ function getTotal() { return items.value .reduce((sum, i) => sum + i.price, 0 ) }
Dans le template : {{ getTotal() }}
Recalculé à chaque rendu, même si rien n'a changé
// Mis en cache automatiquement ✅ const total = computed(() => { return items.value .reduce((sum, i) => sum + i.price, 0 ) })
Dans le template : {{ total }}
Recalculé uniquement si items change
🧠 Cache intelligent
Ne recalcule que si ses dépendances changent
📖 Lecture seule
Retourne une valeur, pas une action
📋 Dans le template
{{ total }} au lieu de {{ getTotal() }}
<script setup> import { ref, watch } from 'vue' const search = ref('') const results = ref([]) // Surveiller 'search' et réagir watch(search, async (newVal, oldVal) => { console.log( `"${oldVal}" → "${newVal}"` ) if (newVal.length >= 3) { const res = await fetch( `/api/search?q=${newVal}` ) results.value = await res.json() } }) </script> <template> <input v-model="search" placeholder="Rechercher..." /> <ul> <li v-for="r in results"> {{ r.name }} </li> </ul> </template>
watch(search, ...) — on déclare ce qu'on surveille
Reçoit la nouvelle et l'ancienne valeur
Idéal pour : appels API, localStorage, logs
Ne se déclenche PAS au premier rendu (par défaut)
Option : { immediate: true }
Pour exécuter le watcher dès le chargement du composant
watch(search, async (val) => { results.value = await fetchAPI(val) })
oldValue et newValue
watchEffect(async () => { results.value = await fetchAPI(search.value) })
oldValue
💡 Conseil
En cas de doute, utilisez watch() — c'est plus explicite et prévisible. Vous savez exactement ce qui est surveillé.
Transformer des données
"Combien de Pokémon de type Feu ?"
const firePokemons = computed(() => pokemons.value.filter( p => p.type === 'Feu' ) )
Réagir à un changement
"Quand la recherche change, appeler l'API"
watch(search, async (val) => { const res = await fetch( `/api?q=${val}` ) results.value = await res.json() })
J'ai besoin d'une VALEUR dérivée
→ computed
filteredPokemons, totalCount, pokemonsByType
J'ai besoin d'un EFFET
→ watch
appel API, sauvegarde localStorage, log
⚠️ Erreur fréquente
Ne pas utiliser watch pour calculer une valeur dérivée — c'est le rôle de computed.
Étapes 8, 9 et 10
fr.vuejs.org/tutorial →
Exercices 5, 6 et 7
kode.ch/vue-bases →
📋 En classe
Tutoriel étapes 8-10 ensemble, puis exercices 5 à 7
📚 Devoirs
Terminer les exercices 5, 6 et 7 pour la prochaine séance
Documentation officielle
Propriétés calculées
Observateurs de données
Apprendre en codant
Support de cours Vue.js
kode.ch/vue-bases
Introduction à Vuetify !
Composants Material Design, grilles et layouts