Table of Contents
Migrer vers la Composition API Vue 3 : Guide Complet
L’arrivee de Vue 3 marque un tournant majeur dans l’ecosysteme Vue.js avec l’introduction de la Composition API. Cette nouvelle approche revolutionne la facon dont nous organisons et reutilisons la logique dans nos composants. Dans ce guide exhaustif, nous allons explorer en profondeur comment migrer vos composants existants vers la Composition API, comprendre ses avantages, et maitriser toutes ses fonctionnalites.
Introduction : Options API vs Composition API
L’Options API : L’approche traditionnelle
Depuis Vue 2, l’Options API a ete la methode standard pour creer des composants. Cette approche organise le code par type d’option : data, methods, computed, watch, etc.
// Options API - Vue 2/3
export default {
data() {
return {
count: 0,
user: null,
isLoading: false
}
},
computed: {
doubleCount() {
return this.count * 2
}
},
methods: {
increment() {
this.count++
},
async fetchUser() {
this.isLoading = true
this.user = await api.getUser()
this.isLoading = false
}
},
mounted() {
this.fetchUser()
}
}
Problemes de l’Options API :
- Fragmentation de la logique : Le code lie a une meme fonctionnalite est disperse entre data, methods, computed, etc.
- Difficulte de reutilisation : Les mixins, la solution historique, causent des conflits de noms et une origine obscure des proprietes
- Typage TypeScript limite : Le contexte
thiscomplique l’inference de types - Composants volumineux : Les gros composants deviennent difficiles a maintenir
La Composition API : Une nouvelle philosophie
La Composition API permet d’organiser le code par fonctionnalite logique plutot que par type d’option :
// Composition API - Vue 3
import { ref, computed, onMounted } from 'vue'
export default {
setup() {
// Logique du compteur
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
const increment = () => count.value++
// Logique de l'utilisateur
const user = ref(null)
const isLoading = ref(false)
const fetchUser = async () => {
isLoading.value = true
user.value = await api.getUser()
isLoading.value = false
}
onMounted(() => {
fetchUser()
})
return { count, doubleCount, increment, user, isLoading }
}
}
Avantages de la Composition API :
- Code organise par fonctionnalite : Toute la logique liee est regroupee
- Reutilisation facile : Les composables remplacent avantageusement les mixins
- Excellent support TypeScript : Inference de types naturelle
- Meilleure testabilite : Les fonctions pures sont faciles a tester
- Tree-shaking optimal : Seules les fonctions importees sont incluses dans le bundle
Section 1 : useStore() et l’acces au store Vuex
Comprendre useStore()
Dans la Composition API, l’acces au store Vuex se fait via la fonction useStore(). Cette fonction doit etre appelee dans le contexte de setup().
import { useStore } from 'vuex'
export default {
setup() {
const store = useStore()
// Acces au state
const users = computed(() => store.state.users)
// Acces aux getters
const activeUsers = computed(() => store.getters.activeUsers)
// Dispatch d'actions
const fetchUsers = () => store.dispatch('fetchUsers')
// Commit de mutations
const addUser = (user) => store.commit('ADD_USER', user)
return { users, activeUsers, fetchUsers, addUser }
}
}
Pattern avance : Helpers pour Vuex
Pour simplifier l’utilisation du store, creez des helpers reutilisables :
// composables/useVuex.js
import { computed } from 'vue'
import { useStore } from 'vuex'
export function useState(keys) {
const store = useStore()
const state = {}
keys.forEach(key => {
state[key] = computed(() => store.state[key])
})
return state
}
export function useGetters(keys) {
const store = useStore()
const getters = {}
keys.forEach(key => {
getters[key] = computed(() => store.getters[key])
})
return getters
}
export function useActions(keys) {
const store = useStore()
const actions = {}
keys.forEach(key => {
actions[key] = (payload) => store.dispatch(key, payload)
})
return actions
}
Utilisation dans un composant :
import { useState, useGetters, useActions } from '@/composables/useVuex'
export default {
setup() {
const { users, products } = useState(['users', 'products'])
const { totalUsers, activeProducts } = useGetters(['totalUsers', 'activeProducts'])
const { fetchUsers, updateProduct } = useActions(['fetchUsers', 'updateProduct'])
return { users, products, totalUsers, activeProducts, fetchUsers, updateProduct }
}
}
Migration de Pinia (alternative moderne)
Si vous envisagez une migration vers Pinia (le successeur officiel de Vuex), la syntaxe est encore plus simple :
import { useUserStore } from '@/stores/user'
export default {
setup() {
const userStore = useUserStore()
// Acces direct aux proprietes reactives
// userStore.users, userStore.fetchUsers(), etc.
return { userStore }
}
}
Section 2 : ref() vs reactive() - Comprendre la reactivite
ref() : Pour les valeurs primitives et les objets
La fonction ref() cree une reference reactive. Elle fonctionne avec tous les types de valeurs.
import { ref } from 'vue'
// Primitives
const count = ref(0)
const name = ref('John')
const isActive = ref(true)
// Objets et tableaux
const user = ref({ name: 'John', age: 30 })
const items = ref([1, 2, 3])
// Acces et modification via .value
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
// Dans le template, .value est automatiquement "unwrap"
// <template>
// <span>{{ count }}</span> <!-- pas besoin de count.value -->
// </template>
reactive() : Pour les objets complexes
La fonction reactive() cree un proxy reactif. Elle ne fonctionne qu’avec les objets.
import { reactive } from 'vue'
const state = reactive({
count: 0,
user: {
name: 'John',
email: 'john@example.com'
},
items: []
})
// Acces direct (pas de .value)
console.log(state.count) // 0
state.count++
// Modification des proprietes imbriquees
state.user.name = 'Jane'
state.items.push({ id: 1 })
Tableau comparatif ref() vs reactive()
| Critere | ref() | reactive() |
|---|---|---|
| Types supportes | Tous (primitifs, objets, tableaux) | Objets uniquement |
| Acces a la valeur | Via .value | Direct |
| Destructuration | Perd la reactivite si on extrait .value | Perd la reactivite |
| Remplacement complet | ref.value = newValue | Non recommande |
| TypeScript | Meilleure inference | Bonne inference |
| Cas d’usage | Valeurs simples, objets remplaceables | Objets complexes stables |
toRef() et toRefs() : Conserver la reactivite
import { reactive, toRef, toRefs } from 'vue'
const state = reactive({
count: 0,
name: 'John'
})
// toRef : creer une ref liee a une propriete reactive
const countRef = toRef(state, 'count')
countRef.value++ // state.count est aussi incremente
// toRefs : convertir toutes les proprietes en refs
const { count, name } = toRefs(state)
// count et name sont maintenant des refs liees a state
Quand utiliser quoi ?
// Utilisez ref() pour :
const isLoading = ref(false) // Booleens
const errorMessage = ref('') // Strings
const selectedId = ref(null) // Valeurs nullables
const userData = ref(null) // Objets qui seront remplaces
// Utilisez reactive() pour :
const formState = reactive({ // Formulaires complexes
firstName: '',
lastName: '',
email: '',
preferences: {
newsletter: true,
notifications: false
}
})
const filters = reactive({ // Etats de filtrage
search: '',
category: 'all',
sortBy: 'date',
order: 'desc'
})
Section 3 : Les Lifecycle Hooks
Vue d’ensemble des hooks
La Composition API fournit des fonctions equivalentes a tous les hooks de l’Options API :
| Options API | Composition API |
|---|---|
beforeCreate | Non necessaire (dans setup) |
created | Non necessaire (dans setup) |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
errorCaptured | onErrorCaptured |
activated | onActivated |
deactivated | onDeactivated |
onMounted : Initialisation apres le rendu
import { ref, onMounted } from 'vue'
export default {
setup() {
const data = ref(null)
const element = ref(null) // template ref
onMounted(async () => {
// Le DOM est maintenant disponible
console.log(element.value) // Element DOM
// Chargement de donnees initial
data.value = await fetchData()
// Initialisation de librairies tierces
initChart(element.value)
})
return { data, element }
}
}
onUpdated : Reagir aux mises a jour du DOM
import { ref, onUpdated } from 'vue'
export default {
setup() {
const items = ref([])
onUpdated(() => {
// Appele apres chaque mise a jour du DOM
console.log('Le DOM a ete mis a jour')
// Attention : peut etre appele frequemment
// Utilisez avec parcimonie
})
return { items }
}
}
onUnmounted : Nettoyage des ressources
import { ref, onMounted, onUnmounted } from 'vue'
export default {
setup() {
const intervalId = ref(null)
const socketConnection = ref(null)
onMounted(() => {
// Demarrer un intervalle
intervalId.value = setInterval(() => {
console.log('tick')
}, 1000)
// Etablir une connexion WebSocket
socketConnection.value = new WebSocket('ws://example.com')
})
onUnmounted(() => {
// IMPORTANT : Nettoyer pour eviter les fuites memoire
if (intervalId.value) {
clearInterval(intervalId.value)
}
if (socketConnection.value) {
socketConnection.value.close()
}
})
return {}
}
}
Pattern : Hook de nettoyage automatique
// composables/useInterval.js
import { onUnmounted } from 'vue'
export function useInterval(callback, delay) {
const intervalId = setInterval(callback, delay)
// Nettoyage automatique lors du demontage
onUnmounted(() => {
clearInterval(intervalId)
})
return intervalId
}
// Utilisation
import { useInterval } from '@/composables/useInterval'
export default {
setup() {
// L'intervalle sera automatiquement nettoye
useInterval(() => {
console.log('tick')
}, 1000)
return {}
}
}
Section 4 : watch() et watchEffect()
watch() : Observation explicite
La fonction watch() permet d’observer des sources reactives specifiques :
import { ref, watch } from 'vue'
export default {
setup() {
const count = ref(0)
const user = ref({ name: 'John' })
// Observer une ref
watch(count, (newValue, oldValue) => {
console.log(`count: ${oldValue} -> ${newValue}`)
})
// Observer avec options
watch(count, (newValue) => {
console.log('count changed:', newValue)
}, {
immediate: true, // Executer immediatement
deep: false, // Observation profonde (pour objets)
flush: 'post' // Timing: 'pre', 'post', 'sync'
})
// Observer une propriete d'objet (fonction getter)
watch(
() => user.value.name,
(newName) => {
console.log('name changed:', newName)
}
)
// Observer plusieurs sources
watch(
[count, () => user.value.name],
([newCount, newName], [oldCount, oldName]) => {
console.log('Multiple values changed')
}
)
return { count, user }
}
}
watchEffect() : Observation automatique
watchEffect() detecte automatiquement les dependances reactives :
import { ref, watchEffect } from 'vue'
export default {
setup() {
const count = ref(0)
const multiplier = ref(2)
// Les dependances sont detectees automatiquement
watchEffect(() => {
// Cette fonction sera re-executee quand count OU multiplier change
console.log(`Result: ${count.value * multiplier.value}`)
})
// watchEffect avec cleanup
watchEffect((onCleanup) => {
const controller = new AbortController()
fetch('/api/data', { signal: controller.signal })
.then(r => r.json())
.then(data => {
// traiter les donnees
})
// Cleanup avant chaque re-execution
onCleanup(() => {
controller.abort()
})
})
return { count, multiplier }
}
}
Arreter un watcher
import { ref, watch, watchEffect } from 'vue'
export default {
setup() {
const data = ref(null)
// watch() et watchEffect() retournent une fonction d'arret
const stopWatch = watch(data, (newVal) => {
console.log('data changed')
})
const stopEffect = watchEffect(() => {
console.log(data.value)
})
// Arreter les watchers manuellement
const stopAll = () => {
stopWatch()
stopEffect()
}
return { data, stopAll }
}
}
Comparaison watch() vs watchEffect()
| Aspect | watch() | watchEffect() |
|---|---|---|
| Dependances | Explicites | Automatiques |
| Valeur precedente | Disponible | Non disponible |
| Execution initiale | Non (sauf immediate: true) | Oui |
| Cas d’usage | Reactions specifiques | Effets de bord generaux |
Section 5 : computed() dans la Composition API
Les bases de computed()
import { ref, computed } from 'vue'
export default {
setup() {
const firstName = ref('John')
const lastName = ref('Doe')
// Computed en lecture seule
const fullName = computed(() => {
return `${firstName.value} ${lastName.value}`
})
// Computed avec getter et setter
const fullNameWritable = computed({
get() {
return `${firstName.value} ${lastName.value}`
},
set(newValue) {
const parts = newValue.split(' ')
firstName.value = parts[0]
lastName.value = parts[1] || ''
}
})
return { firstName, lastName, fullName, fullNameWritable }
}
}
Computed avec dependances complexes
import { ref, computed } from 'vue'
export default {
setup() {
const items = ref([
{ id: 1, name: 'Apple', price: 1.5, category: 'fruits' },
{ id: 2, name: 'Bread', price: 2.0, category: 'bakery' },
{ id: 3, name: 'Milk', price: 1.0, category: 'dairy' }
])
const searchQuery = ref('')
const selectedCategory = ref('all')
const sortBy = ref('name')
// Computed chaine : filtrage puis tri
const filteredItems = computed(() => {
return items.value.filter(item => {
const matchesSearch = item.name
.toLowerCase()
.includes(searchQuery.value.toLowerCase())
const matchesCategory = selectedCategory.value === 'all'
|| item.category === selectedCategory.value
return matchesSearch && matchesCategory
})
})
const sortedItems = computed(() => {
return [...filteredItems.value].sort((a, b) => {
if (sortBy.value === 'name') {
return a.name.localeCompare(b.name)
}
return a.price - b.price
})
})
// Statistiques derivees
const totalPrice = computed(() => {
return sortedItems.value.reduce((sum, item) => sum + item.price, 0)
})
const itemCount = computed(() => sortedItems.value.length)
return {
items,
searchQuery,
selectedCategory,
sortBy,
sortedItems,
totalPrice,
itemCount
}
}
}
Section 6 : Les Composables - Fonctions Reutilisables
Qu’est-ce qu’un composable ?
Un composable est une fonction qui encapsule une logique reutilisable en utilisant la Composition API. C’est le remplacement moderne des mixins.
Exemple : useCounter
// composables/useCounter.js
import { ref, computed } from 'vue'
export function useCounter(initialValue = 0, step = 1) {
const count = ref(initialValue)
const doubleCount = computed(() => count.value * 2)
const isPositive = computed(() => count.value > 0)
const increment = () => count.value += step
const decrement = () => count.value -= step
const reset = () => count.value = initialValue
return {
count,
doubleCount,
isPositive,
increment,
decrement,
reset
}
}
Exemple : useFetch
// composables/useFetch.js
import { ref, watchEffect, toValue } from 'vue'
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
const isLoading = ref(false)
const fetchData = async () => {
isLoading.value = true
error.value = null
try {
const response = await fetch(toValue(url))
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
data.value = await response.json()
} catch (e) {
error.value = e.message
} finally {
isLoading.value = false
}
}
// Re-fetch automatiquement si l'URL change
watchEffect(() => {
if (toValue(url)) {
fetchData()
}
})
return { data, error, isLoading, refetch: fetchData }
}
Exemple : useLocalStorage
// composables/useLocalStorage.js
import { ref, watch } from 'vue'
export function useLocalStorage(key, defaultValue) {
// Lire la valeur initiale
const storedValue = localStorage.getItem(key)
const value = ref(
storedValue ? JSON.parse(storedValue) : defaultValue
)
// Persister les changements
watch(value, (newValue) => {
if (newValue === null || newValue === undefined) {
localStorage.removeItem(key)
} else {
localStorage.setItem(key, JSON.stringify(newValue))
}
}, { deep: true })
return value
}
Exemple : useDebounce
// composables/useDebounce.js
import { ref, watch } from 'vue'
export function useDebounce(value, delay = 300) {
const debouncedValue = ref(value.value)
let timeout
watch(value, (newValue) => {
clearTimeout(timeout)
timeout = setTimeout(() => {
debouncedValue.value = newValue
}, delay)
})
return debouncedValue
}
// Utilisation
import { ref } from 'vue'
import { useDebounce } from '@/composables/useDebounce'
export default {
setup() {
const searchInput = ref('')
const debouncedSearch = useDebounce(searchInput, 500)
// debouncedSearch ne changera que 500ms apres
// la derniere modification de searchInput
return { searchInput, debouncedSearch }
}
}
Section 7 : Exemple Complet de Migration
Composant Options API (Avant)
// UserProfile.vue - Options API
export default {
name: 'UserProfile',
props: {
userId: {
type: Number,
required: true
}
},
data() {
return {
user: null,
posts: [],
isLoading: false,
error: null,
showDetails: false
}
},
computed: {
fullName() {
return this.user
? `${this.user.firstName} ${this.user.lastName}`
: ''
},
postCount() {
return this.posts.length
},
recentPosts() {
return this.posts.slice(0, 5)
}
},
watch: {
userId: {
handler: 'fetchUser',
immediate: true
}
},
methods: {
async fetchUser() {
this.isLoading = true
this.error = null
try {
const response = await fetch(`/api/users/${this.userId}`)
this.user = await response.json()
await this.fetchPosts()
} catch (e) {
this.error = e.message
} finally {
this.isLoading = false
}
},
async fetchPosts() {
const response = await fetch(`/api/users/${this.userId}/posts`)
this.posts = await response.json()
},
toggleDetails() {
this.showDetails = !this.showDetails
}
},
mounted() {
console.log('UserProfile mounted')
},
unmounted() {
console.log('UserProfile unmounted')
}
}
Composant Composition API (Apres)
<!-- UserProfile.vue - Composition API -->
<script setup>
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
// Props
const props = defineProps({
userId: {
type: Number,
required: true
}
})
// State reactif
const user = ref(null)
const posts = ref([])
const isLoading = ref(false)
const error = ref(null)
const showDetails = ref(false)
// Computed
const fullName = computed(() => {
return user.value
? `${user.value.firstName} ${user.value.lastName}`
: ''
})
const postCount = computed(() => posts.value.length)
const recentPosts = computed(() => posts.value.slice(0, 5))
// Methodes
const fetchUser = async () => {
isLoading.value = true
error.value = null
try {
const response = await fetch(`/api/users/${props.userId}`)
user.value = await response.json()
await fetchPosts()
} catch (e) {
error.value = e.message
} finally {
isLoading.value = false
}
}
const fetchPosts = async () => {
const response = await fetch(`/api/users/${props.userId}/posts`)
posts.value = await response.json()
}
const toggleDetails = () => {
showDetails.value = !showDetails.value
}
// Watcher
watch(
() => props.userId,
() => fetchUser(),
{ immediate: true }
)
// Lifecycle hooks
onMounted(() => {
console.log('UserProfile mounted')
})
onUnmounted(() => {
console.log('UserProfile unmounted')
})
</script>
Version avec Composables (Optimale)
// composables/useUser.js
import { ref, computed, watch } from 'vue'
export function useUser(userId) {
const user = ref(null)
const isLoading = ref(false)
const error = ref(null)
const fullName = computed(() => {
return user.value
? `${user.value.firstName} ${user.value.lastName}`
: ''
})
const fetchUser = async () => {
isLoading.value = true
error.value = null
try {
const response = await fetch(`/api/users/${userId.value}`)
user.value = await response.json()
} catch (e) {
error.value = e.message
} finally {
isLoading.value = false
}
}
watch(userId, fetchUser, { immediate: true })
return { user, fullName, isLoading, error, refetch: fetchUser }
}
// composables/usePosts.js
import { ref, computed } from 'vue'
export function usePosts(userId) {
const posts = ref([])
const postCount = computed(() => posts.value.length)
const recentPosts = computed(() => posts.value.slice(0, 5))
const fetchPosts = async () => {
const response = await fetch(`/api/users/${userId.value}/posts`)
posts.value = await response.json()
}
return { posts, postCount, recentPosts, fetchPosts }
}
<!-- UserProfile.vue - Avec Composables -->
<script setup>
import { ref, toRef, onMounted, onUnmounted } from 'vue'
import { useUser } from '@/composables/useUser'
import { usePosts } from '@/composables/usePosts'
const props = defineProps({
userId: {
type: Number,
required: true
}
})
const userIdRef = toRef(props, 'userId')
// Utilisation des composables
const { user, fullName, isLoading, error } = useUser(userIdRef)
const { posts, postCount, recentPosts, fetchPosts } = usePosts(userIdRef)
// State local
const showDetails = ref(false)
const toggleDetails = () => showDetails.value = !showDetails.value
// Lifecycle
onMounted(() => {
fetchPosts()
console.log('UserProfile mounted')
})
onUnmounted(() => {
console.log('UserProfile unmounted')
})
</script>
Section 8 : Tableau Comparatif Complet
| Aspect | Options API | Composition API |
|---|---|---|
| Organisation du code | Par type d’option | Par fonctionnalite |
| Reutilisation | Mixins (problematique) | Composables (elegant) |
| Support TypeScript | Limite | Excellent |
| Tree-shaking | Tout est inclus | Imports selectifs |
| Courbe d’apprentissage | Douce | Moderee |
| Lisibilite | Bonne pour petits composants | Excellente pour grands composants |
| Testabilite | Necessite mount | Fonctions pures testables |
Acces a this | Oui | Non (pas necessaire) |
| Reactivity refs | Implicite via data() | Explicite via ref()/reactive() |
| Lifecycle hooks | Options dans l’objet | Fonctions importees |
Section 9 : Bonnes Pratiques
1. Preferez <script setup> pour les nouveaux composants
<!-- Recommande -->
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<!-- Moins concis -->
<script>
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
return { count }
}
}
</script>
2. Nommez vos composables avec le prefixe use
// Bon
export function useUser() { }
export function useFetch() { }
export function useLocalStorage() { }
// Mauvais
export function getUser() { }
export function fetchData() { }
export function storage() { }
3. Retournez toujours un objet depuis vos composables
// Bon - permet la destructuration
export function useCounter() {
const count = ref(0)
const increment = () => count.value++
return { count, increment }
}
// Utilisation flexible
const { count } = useCounter()
const counter = useCounter()
4. Gerez toujours le nettoyage dans onUnmounted
export function useEventListener(target, event, callback) {
onMounted(() => {
target.addEventListener(event, callback)
})
// IMPORTANT : toujours nettoyer
onUnmounted(() => {
target.removeEventListener(event, callback)
})
}
5. Utilisez toRef/toRefs pour les props dans les composables
// Dans le composant
const props = defineProps(['userId'])
const { user } = useUser(toRef(props, 'userId'))
// Dans le composable
export function useUser(userId) {
// userId reste reactif meme si c'est une prop
watch(userId, () => fetchUser())
}
6. Evitez les effets de bord dans les computed
// Mauvais - effet de bord dans computed
const total = computed(() => {
console.log('Calculating...') // Effet de bord
localStorage.setItem('total', sum) // Effet de bord
return items.value.reduce((a, b) => a + b, 0)
})
// Bon - computed pur
const total = computed(() => {
return items.value.reduce((a, b) => a + b, 0)
})
// Utilisez watch pour les effets de bord
watch(total, (newTotal) => {
console.log('Total changed:', newTotal)
localStorage.setItem('total', newTotal)
})
Section 10 : Pieges Courants a Eviter
1. Oublier .value avec ref()
// Erreur courante
const count = ref(0)
count++ // Ne fonctionne pas !
console.log(count) // Affiche l'objet Ref, pas la valeur
// Correct
count.value++
console.log(count.value)
2. Destructurer reactive() perd la reactivite
const state = reactive({ count: 0, name: 'John' })
// MAUVAIS - perd la reactivite
const { count, name } = state
count++ // Ne met pas a jour state.count !
// BON - utiliser toRefs
const { count, name } = toRefs(state)
count.value++ // Met a jour state.count
3. Appeler des composables en dehors de setup()
// MAUVAIS - ne fonctionne pas
const handleClick = () => {
const { data } = useFetch('/api/data') // Erreur !
}
// BON - appeler dans setup
const { data, refetch } = useFetch('/api/data')
const handleClick = () => {
refetch() // Utiliser la fonction retournee
}
4. Creer des watchers infinis
// MAUVAIS - boucle infinie
const count = ref(0)
watch(count, () => {
count.value++ // Declenche le watcher encore !
})
// BON - utiliser une condition
watch(count, (newVal) => {
if (newVal < 10) {
count.value++
}
})
5. Ne pas typer correctement avec TypeScript
// MAUVAIS - type any implicite
const user = ref(null)
// BON - typage explicite
interface User {
id: number
name: string
email: string
}
const user = ref<User | null>(null)
Conclusion
La migration vers la Composition API de Vue 3 represente une evolution majeure dans la facon dont nous structurons nos applications Vue. En adoptant cette nouvelle approche, vous beneficiez de :
- Une meilleure organisation du code grace au regroupement logique
- Une reutilisabilite accrue avec les composables
- Un support TypeScript natif pour des applications plus robustes
- Une performance optimisee grace au tree-shaking
- Une maintenance simplifiee pour les projets de grande envergure
La cle d’une migration reussie reside dans une approche progressive : commencez par les nouveaux composants, puis migrez progressivement les composants existants en utilisant les patterns et composables presentes dans ce guide.
N’oubliez pas que l’Options API reste parfaitement valide dans Vue 3. La Composition API est une option supplementaire, pas un remplacement obligatoire. Choisissez l’approche qui convient le mieux a votre equipe et a votre projet.
Ressources Complementaires
- Documentation officielle Vue 3
- API de la Composition API
- VueUse - Collection de Composables
- Pinia - Store Vue 3
- Vue 3 Migration Guide
La maitrise de la Composition API ouvre la porte a des applications Vue plus maintenables, testables et performantes. Prenez le temps d’experimenter avec les differents concepts presentes ici, et n’hesitez pas a creer vos propres composables pour encapsuler la logique metier de votre application.
In-Article Ad
Dev Mode
Tags
Mahmoud DEVO
Senior Full-Stack Developer
I'm a passionate full-stack developer with 10+ years of experience building scalable web applications. I write about Vue.js, Node.js, PostgreSQL, and modern DevOps practices.
Enjoyed this article?
Subscribe to get more tech content delivered to your inbox.
Related Articles
Gestion de Formulaires avec Vuex : Mutations, Getters et Actions
Maîtrisez la gestion des formulaires avec Vuex. Créez des mutations pour chaque champ, des getters pour l'état et des actions pour les API.
Introduction à la Composition API Vue.js : setup(), ref() et reactive()
Découvrez la Composition API de Vue 3. Maîtrisez setup(), ref() pour les primitives et reactive() pour les objets avec des exemples pratiques.
Implementation d'un Mode Sombre avec Vue.js et la Composition API
Creez un mode sombre elegant avec Vue.js et les composables. Utilisez ref, les CSS variables et localStorage pour persister le theme.