Il y a les notes de version, et il y a le ressenti réel en développement. En passant de Vue 2 à Vue 3 sur une application concrète, voici ce qui m’a sauté aux yeux. Pas de comparatif exhaustif ici, juste ce qui compte pour coder.
Composition API : un autre paradigme
Le changement le plus visible (et structurant), c’est la Composition API.
L’approche setup()
centralise les logiques au lieu de les disperser dans data
, methods
, computed
et compagnie. On gagne en lisibilité sur des composants complexes, surtout quand plusieurs blocs de logique doivent interagir.
Avant (Vue 2) :
export default {
data() { return { count: 0 }; },
methods: {
increment() { this.count++ }
}
}
Après (Vue 3) :
export default {
setup() {
const count = ref(0)
const increment = () => count.value++
return { count, increment }
}
}
Au début, c’est plus verbeux. Mais sur le moyen terme, ça clarifie tout. Et surtout, on peut extraire ses logiques dans des fonctions réutilisables.
La réactivité avec ref
et reactive
Autre changement fondamental : fini les objets magiques dans data
. Avec Vue 3, on utilise ref()
pour les primitives et reactive()
pour les objets. Et on manipule .value
.
C’est plus explicite, mais aussi plus rigide. Il faut oublier les raccourcis de Vue 2.
Les watch
et computed
gagnent en souplesse
watch
accepte désormais des fonctions directement, ce qui évite les chaînes de caractères ou les bizarreries de dépendance implicite.
watch(() => props.id, (newId) => {
// logique
})
computed
fonctionne à peu près pareil mais est devenu encore plus puissant avec la possibilité de le rendre writable.
Data flow : plus clair, plus contrôlé, plus explicite
Le flux de données dans Vue 3 est devenu plus strict, mais aussi plus lisible et prévisible.
- Les props sont inchangées dans leur usage, mais leur typage est mieux pris en charge, notamment avec
defineProps()
dans les<script setup>
. - Les événements émis doivent être déclarés avec
defineEmits()
(ouemits: []
), ce qui renforce la clarté du contrat d’un composant : on sait ce qu’il accepte et ce qu’il renvoie.
const emit = defineEmits(['submit'])
emit('submit', formData)
Fini les magies silencieuses de $listeners
, $attrs
, $scopedSlots
: tout est maintenant explicite. Si on veut transmettre des props ou des events, on le fait à la main avec v-bind="attrs"
ou via les objets fournis.
Les attrs et slots sont accessibles via useAttrs()
et useSlots()
dans un setup()
, ce qui permet un meilleur contrôle sur ce qu’on laisse passer au composant enfant.
Plus besoin de Vue.extend
, et defineComponent
devient la norme
Avec TypeScript, defineComponent()
est une bénédiction. Même sans TS, ça structure mieux. Mais ça rajoute une couche à digérer pour ceux qui codent à l’instinct.
Global API changée : attention aux plugins
Plus de Vue.use()
, on passe par app.use()
dans un fichier dédié :
const app = createApp(App)
app.use(router)
app.use(pinia)
app.mount('#app')
C’est plus logique, surtout pour les SSR/Nuxt-like, mais ça demande une adaptation pour les anciens plugins non mis à jour.
Conclusion : plus rigide, mais plus propre
Vue 3 impose une discipline. Au début, on comprends rien, on se dit que c’est du React. Puis on comprend que ça pousse à écrire du code modulaire, testable, maintenable.
C’est une refonte en profondeur : ce n’est pas juste une version « améliorée », c’est une nouvelle façon de penser ses composants.
Si tu as besoin d’un dev Vue pour coder ton application :