Pourquoi Composition API Vue 3 ?
L'API Composition est un nouveau modèle d'écriture des composants Vue.js introduit avec la version 3. Cette nouvelle approche permet une meilleure gestion de l'état, des effets de bord et de la logique réutilisable dans les composants.
Dans le contexte professionnel, un développeur peut se retrouver confronté à des composants complexes nécessitant beaucoup de logique interne. Avec Vue 2, il y a souvent eu une fragmentation du code avec des méthodes data, methods, et computed qui ont tendance à s'étaler sur plusieurs fichiers ou même être répétées dans différents composants similaires.
En utilisant la Composition API, on peut regrouper logiquement les différentes parties d'une fonctionnalité plutôt que de les organiser par type (data, methods), ce qui rend le code plus organisé et plus facile à comprendre. De plus, elle offre des avantages tels que la reutilisation plus simple du code et une meilleure gestion des effets de bord asynchrones.
Un cas concret est l'implémentation d'un formulaire avec validation complexe. Vue 2 nécessiterait probablement plusieurs méthodes et hooks pour gérer les états, validations et soumissions. Avec la Composition API, on peut regrouper ces responsabilités dans une fonction personnalisée, facilitant le maintien et la réutilisation du code.
Prerequis
Connaissances nécessaires :
- Vue.js version 3
- JavaScript ES6+
- Concepts de base de React ou Angular (optionnel mais recommandé)
Outils à installer :
- Node.js (version recommandée: 14.x)
- npm (node package manager)
- Visual Studio Code ou un éditeur de code moderne
Concepts fondamentaux
setup()
La fonction setup() est le cœur de l'API Composition. Elle est exécutée avant la création du composant et retourne des valeurs que vous pouvez utiliser dans le template, les méthodes et autres fonctions.
<script>
import { ref, onMounted } from 'vue';
export default {
setup() {
const count = ref(0);
const increment = () => {
count.value++;
};
onMounted(() => {
console.log('Component is mounted!');
});
return {
count,
increment
};
}
};
</script>
ref() et reactive()
ref() est utilisé pour créer des propriétés réactives simples, tandis que reactive() est utilisé pour créer des objets entiers qui sont tout à fait réactifs.
<script>
import { ref, reactive } from 'vue';
export default {
setup() {
const count = ref(0);
const state = reactive({
name: 'Vue',
version: 3
});
return {
count,
state
};
}
};
</script>
computed()
computed() permet de créer des propriétés calculées basées sur d'autres propriétés réactives.
<script>
import { ref, computed } from 'vue';
export default {
setup() {
const firstName = ref('John');
const lastName = ref('Doe');
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
return {
firstName,
lastName,
fullName
};
}
};
</script>
watch() et watchEffect()
watch() permet de surveiller les changements sur une ou plusieurs propriétés réactives, tandis que watchEffect() exécute immédiatement la fonction passée et la re-exécute à chaque changement.
<script>
import { ref, watch, watchEffect } from 'vue';
export default {
setup() {
const count = ref(0);
watch(count, (newVal, oldVal) => {
console.log(`count changed from ${oldVal} to ${newVal}`);
});
watchEffect(() => {
console.log(`Current count is: ${count.value}`);
});
return {
count
};
}
};
</script>
provide() et inject()
provide() permet de partager des données entre composants, tandis que inject() les récupère.
<script>
import { provide, ref } from 'vue';
export default {
setup() {
const user = ref({ name: 'John', age: 30 });
provide('user', user);
return {};
}
};
</script>
<!-- Enfant -->
<script>
import { inject } from 'vue';
export default {
setup() {
const user = inject('user');
return {
user
};
}
};
</script>
Mise en pratique : projet fil rouge
Mini-projet complet : Gestionnaire de tâches
Dans cet exemple, nous allons créer un gestionnaire de tâches simple avec des fonctionnalités de création, affichage et suppression de tâches.
Étape 1 : Créer le projet
npm init vue@latest task-manager-app
cd task-manager-app
npm install
Étape 2 : Créer le composant TaskList.vue
<template>
<div>
<h1>Task Manager</h1>
<ul v-if="tasks.length">
<li v-for="(task, index) in tasks" :key="index">
task.name - task.completed ? 'Done' : 'Pending'
<button @click="toggleTask(index)">Toggle</button>
<button @click="deleteTask(index)">Delete</button>
</li>
</ul>
<p v-else>No tasks found.</p>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const tasks = ref([
{ name: 'Buy groceries', completed: false },
{ name: 'Clean the house', completed: true }
]);
const addTask = (taskName) => {
if (taskName.trim()) {
tasks.value.push({ name: taskName, completed: false });
}
};
const toggleTask = (index) => {
tasks.value[index].completed = !tasks.value[index].completed;
};
const deleteTask = (index) => {
tasks.value.splice(index, 1);
};
return {
tasks,
addTask,
toggleTask,
deleteTask
};
}
};
</script>
Étape 3 : Créer le composant App.vue et intégrer TaskList
<template>
<div id="app">
<h1>Vue 3 Task Manager</h1>
<input v-model="newTask" @keyup.enter="addTask(newTask)" placeholder="Add a new task" />
<button @click="addTask(newTask)">Add</button>
<TaskList :tasks="tasks" />
</div>
</template>
<script>
import { ref } from 'vue';
import TaskList from './components/TaskList.vue';
export default {
components: {
TaskList
},
setup() {
const newTask = ref('');
const tasks = ref([]);
const addTask = (taskName) => {
if (taskName.trim()) {
tasks.value.push({ name: taskName, completed: false });
newTask.value = '';
}
};
return {
newTask,
tasks,
addTask
};
}
};
</script>
Étape 4 : Exécuter le projet
npm run dev
Erreurs fréquentes et debugging
1. TypeError: Cannot read property 'value' of undefined
Code incorrect :
<script>
import { ref } from 'vue';
export default {
setup() {
const count; // Missing initialization
return {
count
};
}
};
</script>
Code correct :
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0); // Initialized with ref
return {
count
};
}
};
</script>
2. Uncaught TypeError: Cannot read property 'push' of undefined
Code incorrect :
<script>
import { reactive } from 'vue';
export default {
setup() {
const tasks; // Missing initialization
return {
tasks
};
}
};
</script>
Code correct :
<script>
import { reactive } from 'vue';
export default {
setup() {
const tasks = reactive({ list: [] }); // Initialized with reactive and an empty array
return {
tasks
};
}
};
</script>
3. Uncaught TypeError: Cannot read property 'map' of undefined
Code incorrect :
<script>
import { ref } from 'vue';
export default {
setup() {
const tasks; // Missing initialization
return {
tasks
};
}
};
</script>
Code correct :
<script>
import { ref } from 'vue';
export default {
setup() {
const tasks = ref([]); // Initialized with an empty array
return {
tasks
};
}
};
</script>
Pour aller plus loin
1. Composition API avec TypeScript
La Composition API est idéale pour les projets utilisant TypeScript, car elle permet une meilleure typage des données et de la logique.
- Documentation : Composition API with TypeScript
2. Avancer avec les Hooks personnalisés
Les hooks personnalisés sont une excellente façon de réutiliser la logique entre différents composants.
- Documentation : Custom Composables
3. Intégrer Composition API avec les tests unitaires
Avec des tests unitaires solides, vous pouvez améliorer la qualité et le maintien de votre code.
- Documentation : Testing with Vue Test Utils
Défi pratique : Gestionnaire de notes
Créez un gestionnaire de notes simple avec des fonctionnalités de création, affichage et suppression de notes. Utilisez la Composition API pour structurer le code. Assurez-vous d'utiliser ref pour les états et computed pour des propriétés calculées si nécessaire.