Comment réutiliser la logique dans Vue.js avec Composables



Dans le domaine de la programmation, l’organisation de la base de code est primordiale pour une réutilisation efficace. La duplication de code, en particulier dans les applications volumineuses, peut alourdir la base et rendre le débogage plus ardu.

Vue propose une solution élégante pour la réutilisation du code : les composables. Ce sont des fonctions qui encapsulent une logique spécifique et peuvent être réutilisées dans divers contextes du projet, afin de gérer des fonctionnalités similaires de manière centralisée.

Le chemin vers les composables

Avant l’avènement des composables avec Vue 3, les mixins étaient la solution privilégiée pour extraire du code et le réutiliser dans différentes parties d’une application. Les mixins contenaient des options Vue.js telles que des données, des méthodes et des hooks de cycle de vie, permettant une réutilisation du code entre plusieurs composants.

Pour créer des mixins, ils étaient définis dans des fichiers séparés, puis intégrés aux composants en les ajoutant à la propriété mixins de l’objet options du composant. Voici un exemple:

export const formValidationMixin = {
    data() {
      return {
        formData: {
          username: '',
          password: '',
        },
        formErrors: {
          username: '',
          password: '',
        },
      };
    },
    methods: {
      validateForm() {
        this.formErrors = {};

        if (!this.formData.username.trim()) {
          this.formErrors.username="Le nom d'utilisateur est requis.";
        }

        if (!this.formData.password.trim()) {
          this.formErrors.password = 'Le mot de passe est requis.';
        }
       
        return Object.keys(this.formErrors).length === 0;
      },
    },
  };

Cet exemple présente un mixin dédié à la validation de formulaires. Il comprend deux propriétés de données, formData et formErrors, initialement vides.

formData est utilisé pour stocker les entrées du formulaire, notamment les champs nom d’utilisateur et mot de passe, tandis que formErrors contient les éventuels messages d’erreur.

Le mixin inclut une méthode validateForm() pour vérifier si les champs nom d’utilisateur et mot de passe sont remplis. En cas de champ vide, un message d’erreur correspondant est ajouté à la propriété formErrors.

La méthode retourne true si le formulaire est valide, c’est-à-dire si formErrors est vide. Pour utiliser ce mixin, il faut l’importer dans un composant Vue et l’ajouter à la propriété mixin de l’objet Options :

  <template>
    <div>
      <form @submit.prevent="submitForm">
        <div>
          <label for="username">Nom d'utilisateur:</label>
          <input type="text" id="username" v-model="formData.username" />
          <span class="error">{{ formErrors.username }}</span>
        </div>
        <div>
          <label for="password">Mot de passe:</label>
          <input type="password" id="password" v-model="formData.password" />
          <span class="error">{{ formErrors.password }}</span>
        </div>
        <button type="submit">Soumettre</button>
      </form>
    </div>
  </template>
  <script>
  import { formValidation } from "./formValidation.js";
  
  export default {
    mixins: [formValidation],
    methods: {
      submitForm() {
        if (this.validateForm()) {
          alert("Formulaire soumis avec succès!");
        } else {
          alert("Veuillez corriger les erreurs dans le formulaire.");
        }
      },
    },
  };
  </script>
  
  <style>
  .error {
    color: red;
  }
  </style>

Cet exemple illustre un composant Vue utilisant l’approche des objets Options. La propriété mixins référence les mixins importés. Ici, le composant utilise la méthode validateForm du mixin formValidation pour notifier l’utilisateur du succès ou de l’échec de la soumission du formulaire.

Utilisation des composables

Un composable est un fichier JavaScript autonome qui contient des fonctions conçues pour répondre à des préoccupations ou des exigences spécifiques. Il tire parti de l’API de composition de Vue, notamment des fonctionnalités telles que les refs et les computed refs.

L’accès à l’API de composition permet de créer des fonctions qui peuvent être intégrées dans différents composants. Ces fonctions retournent généralement un objet, qui peut être facilement importé et intégré dans les composants Vue via la fonction setup de l’API de composition.

Pour utiliser un composable, créez un nouveau fichier JavaScript dans le répertoire src de votre projet. Pour les projets de grande envergure, il est conseillé d’organiser les composables dans un dossier dédié, avec des fichiers JavaScript distincts pour chaque composable, dont le nom reflète l’objectif.

Dans ce fichier JavaScript, définissez la fonction souhaitée. Voici une restructuration du mixin formValidation en composable :

  import { reactive } from 'vue';

  export function useFormValidation() {
    const state = reactive({
      formData: {
        username: '',
        password: '',
      },
      formErrors: {
        username: '',
        password: '',
      },
    });
  
    function validateForm() {
      state.formErrors = {};
  
      if (!state.formData.username.trim()) {
        state.formErrors.username="Le nom d'utilisateur est requis.";
      }
  
      if (!state.formData.password.trim()) {
        state.formErrors.password = 'Le mot de passe est requis.';
      }
  
      return Object.keys(state.formErrors).length === 0;
    }
  
    return {
      state,
      validateForm,
    };
  }

Cet extrait commence par importer la fonction reactive du package vue. Il définit ensuite une fonction exportable, useFormValidation().

Cette fonction crée une variable réactive, state, qui contient les propriétés formData et formErrors. La logique de validation du formulaire est implémentée de manière très similaire à celle du mixin. Enfin, la fonction retourne l’état et la fonction validateForm sous forme d’objet.

L’utilisation de ce composable se fait en important la fonction JavaScript dans votre composant :

  <template>
    <div>
      <form @submit.prevent="submitForm">
        <div>
          <label for="username">Nom d'utilisateur:</label>
          <input type="text" id="username" v-model="state.formData.username" />
          <span class="error">{{ state.formErrors.username }}</span>
        </div>
        <div>
          <label for="password">Mot de passe:</label>
          <input type="password" id="password" v-model="state.formData.password" />
          <span class="error">{{ state.formErrors.password }}</span>
        </div>
        <button type="submit">Soumettre</button>
      </form>
    </div>
  </template>
  <script setup>
  import { useFormValidation } from "./formValidation.js";
  import { ref } from "vue";
  const { state, validateForm } = useFormValidation();
  
  const submitForm = () => {
    if (validateForm()) {
      alert("Formulaire soumis avec succès!");
    } else {
      alert("Veuillez corriger les erreurs dans le formulaire.");
    }
  };
  </script>
  
  <style>
  .error {
    color: red;
  }
  </style>

Après avoir importé le composable useFormValidation, ce code déstructure l’objet JavaScript qu’il retourne pour ensuite valider le formulaire. Le composant signale ensuite si la soumission du formulaire s’est bien déroulée ou s’il contient des erreurs.

Les composables, les nouveaux mixins

Bien que les mixins aient été utiles dans Vue 2 pour la réutilisation du code, les composables ont pris leur place dans Vue 3. Les composables offrent une approche plus structurée et maintenable pour réutiliser la logique dans les applications Vue.js, simplifiant ainsi la création d’applications Web évolutives avec Vue.