Vuejs 3 : présentation de la composition api

6 mai 2021 12:57 dans data-pipelines / publications

Vue 3 change la donne. Maintenant mainstream cette release apporte des changements majeurs concernant l'architecture d'un projet Vue. La nouvelle composition api permet d'adopter une architecture plus fluide, plus proche d'une logique métier. A noter le support de premier ordre de Typescript dans cette version.

Slider Image

Vuejs 3 : présentation de la composition api

Vue 3 change la donne. Maintenant mainstream cette release apporte des changements majeurs concernant l'architecture d'un projet Vue. La nouvelle composition api permet d'adopter une organisation du code plus fluide, plus proche d'une logique métier. A noter le support de premier ordre de Typescript dans cette version. Les exemples de code dans cet article utilisent Typescript. Le code des exemples contenu dans cet article est disponible sur Github

Les bases de la composition api

Le code d'un composant est entièrement contenu dans un objet setup. A la différence de la classique options api le code n'a pas à être divisé en unités fonctionnelles (data, methods, computed, ...). Ceci permet l'abolition du keyword this et de son ambiguïté liée au contexte. Exemple de déclaration de composant:


                import { defineComponent } from "vue";

                export default defineComponent({
                  setup() {
                    // le composant est défini ici
                  }
                });
            

Ajoutons des data et des méthodes comme nous le ferions avec la options api. Tout s'effectue dans setup. Noter l'objet retourné par la fonction, qui va exposer les éléments que l'on souhaite utiliser dans le template:


              import { defineComponent } from "vue";

              export default defineComponent({
                setup() {
                  // comme data dans l'options api
                  const myvar = 3;

                  // définition d'une méthode
                  function increment(): number {
                    return myvar + 1;
                  }

                  // l'objet retourné contenant les éléments qui
                  // seront exposés dans le template
                  return {
                    myvar,
                    increment
                  }
                }
              });
          

Nouveau système de réactivité

Vue 3 propose un nouveau système indépendant de gestion de la réactivité. Basé sur les proxy objects ES6 il offre trois types principaux d'objets: ref, reactive et computed.

L'objet ref: la base

L'objet ref est réactif et peut être lu et écrit. Cela permet de définir une variable réactive mutable. L'avantage de cet objet est son caractère explicite, via l'utilisation de sa propriété value. Exemple:


                setup() {
                  // on définit une variable réactive
                  const myvar = ref<number>(1);

                  // pour lire cette ref on utilise le mot clé value
                  console.log(myvar.value);

                  // une méthode pour agir sur la variable
                  function mutateFoo(): number {
                    // noter l'utilisation de value pour muter une ref
                    ++myvar.value;
                  }

                  return {
                    myvar,
                    mutateFoo
                  }
                }
            

Créons un template et utilisons la variable exactement comme on le ferait avec le classique data:

Rendu du template:

ref

 

La mutation sur ref sera reflétée dans le template

L'objet reactive: pour les data structures plus complexes

L'objet reactive sert a gérer les variables de type objet et offre une réactivité en profondeur: il est possible de muter seulement une propriété d'un objet reactive.


          setup() {
            // on définit une variable réactive pour un objet
            const state = reactive({
              counter: {
                currentValue: 1,
                max: 10,
              },
            });
        
            // pas besoin d'utiliser le keyword value comme pour ref
            // pour accéder à la valeur de la variable
            console.log(`current counter value is ${state.counter.currentValue}`);
        
            // définissons une méthode pour muter une propriété
            // de la variable réactive state
            function increment() {
              if (state.counter.currentValue < state.counter.max) {
                ++state.counter.currentValue;
              } else {
                console.log("The counter has reached the maximum");
              }
            }
        
            return {
              state,
              increment,
            };
          },
        

La variable réactive s'utilise dans un template de la même manière

refref

En résumé: cet objet est pratique pour les structures imbriquées et rend les propriétés réactives. Il ne nécessite pas l'utilisation du keyword value comme pour ref.

L'objet computed: pour les variables réactives en lecture seule

Cet objet fonctionne exactement comme la section computed dans l'option api classique. Une computed variable sera en lecture seule. Complétons le code ci-dessus avec une computed property:


            setup() {
              const state = reactive({
                counter: {
                  currentValue: 1,
                  max: 10,
                },
              });
              
              // on crée une computed property pour lire le state
              const isCounterBlocked = computed(() => {
                return state.counter.currentValue >= state.counter.max;
              });
          
              // le mot clé value est utilisé ici comme pour ref
              console.log(`current is blocked ${isCounterBlocked.value}`);
          
              function increment() {
                // on utilise ici la computed prop
                if (!isCounterBlocked.value === true) {
                  ++state.counter.currentValue;
                } else {
                  console.log("The counter has reached the maximum");
                }
              }
          
              return {
                state,
                increment,
                isCounterBlocked,
              };
            },
          

L'utilisation en template reste classique :

State management: les nouvelles possibilités

Le système de réactivité indépendant de Vue 3 permet de simplifier le state management. Cela rend possible la définition d'un state local ou global utilisable par plusieurs composants. Utilisons une variable de type reactive pour définir un state local. Dans un fichier state.ts:


            import { reactive } from "@vue/reactivity";

            // ce state pourra être importé dans les composants
            const state = reactive({
              counter: {
                currentValue: 1,
                max: 10,
              }
            });
            
            export default state;
          

Utilisons ce state dans des composants distincts. On importe le state dans le composant 1 et on définit une mutation:

Dans le composant 2 le state sera réactif à la mutation effectuée dans le composant 1:

ref
 

Note: le compteur ne sera pas réinitialisé en cas de navigation et de retour sur la page: le state étant indépendant du composant et stocké en mémoire il sera préservé lors de la navigation.

Ce pattern simple permet une gestion fine du state et de sa portée. Il convient particulièrement pour des applications simples et permet de s'affranchir de la complexité d'un store Vuex. Pour illustrer la flexibilité possible dans l'exemple ci-dessus la mutation du state a lieu directement dans le composant 1 mais pourrait être définie dans le state.ts, suivant le pattern classique du store.

Notons que l'utilisation du pattern du store et les garanties qu'il apporte reste tout à fait possible pour les applications plus importantes.

Conclusion

Vue 3 apporte beaucoup de par sa composition api. Une organisation du code plus flexible et plus centrée sur la logique métier devient possible. Le système de réactivité apporte de son coté une souplesse bienvenue en termes de state management.

Enfin l'excellent support de Typescript dans la composition api apporte avec lui toutes les garanties du typage statique, rendant les applications plus solides.

Le code des exemples figurant dans cet article est disponible sur Github