Implémentation d'un bus d'événements pour la communication entre composants dans Vue.js

Dans les applications Vue.js, la communication entre composants parents et enfants est généralement gérée via les props et les événements $emit. Cependant, lorsque deux composants n'ont aucune relation hiérarchique directe ou ne s'importent pas mutuellement, une approche différente est nécessaire. Si l'utilisation d'un gestionnaire d'état complet comme Vuex semble excessif pour de simples échanges de données, le modèle du bus d'événements (EventBus) offre une alternative légère.

Le concept d'EventBus agit comme un centre de notification centralisé. Tous les composants peuvent s'y abonner ou y publier des événements, permettant une communication horizontale et transversale. Bien que pratique, une utilisation non contrôlée peut rendre le flux de données difficile à tracer, d'où l'importance de bien gérer les cycles de vie des écouteurs pour éviter les effets de bord.

Initialisation du bus d'événements

La première étape consiste à instancier un objet Vue vierge qui servira de canal. Deux approches principales existent.

Approche 1 : Module dédié

Créez un fichier séparé pour isoler l'instance et l'exporter.

// message-hub.js
import Vue from 'vue';
export const MessageHub = new Vue();

Cette instance n'a pas de template DOM, elle ne sert qu'à exploiter les méthodes réactives de Vue de manière très légère.

Approche 2 : Injection globale

Vous pouvez attacher le bus directement au prototype de Vue dans votre point d'entrée pour le rendre accessbile partout.

// main.js
import Vue from 'vue';
Vue.prototype.$appHub = new Vue();

Émission et réception de signaux

Supposons que nous ayons deux vues distinctes, Dashboard et Settings, qui doivent échanger des informations sans être liées.

Émission (Dashboard)

La vue Dashboard déclenche un événement lors d'une action utilisateur.

<!-- Dashboard.vue -->
<template>
  <button @click="triggerUpdate">Mettre à jour</button>
</template>

<script>
import { MessageHub } from './message-hub.js';

export default {
  methods: {
    triggerUpdate() {
      const payload = { status: 'success', timestamp: Date.now() };
      MessageHub.$emit('sync-state-change', payload);
    }
  }
};
</script>

Réception (Settings)

La vue Settings écoute ce canal spécifique pour réagir aux changements.

<!-- Settings.vue -->
<template>
  <div>
    <p>Statut actuel : {{ currentState }}</p>
  </div>
</template>

<script>
import { MessageHub } from './message-hub.js';

export default {
  data() {
    return {
      currentState: 'En attente...'
    };
  },
  mounted() {
    MessageHub.$on('sync-state-change', (data) => {
      this.currentState = `Mis à jour à ${data.timestamp}`;
    });
  }
};
</script>

Gestion de la mémoire et nettoyage

Dans une Single Page Application (SPA), si un composant est détruit mais que son écouteur d'événement reste actif sur le bus, cela provoque des fuites de mémoire et des exécutions fantômes lors de navigations répétées. Il est impératif de désabonner les écouteurs lors de la destruction du composant.

Utilisez le hook beforeDestroy pour nettoyer les abonnements :

// Dans Settings.vue
export default {
  // ...
  beforeDestroy() {
    // Supprime l'écouteur spécifique
    MessageHub.$off('sync-state-change');
    
    // Ou pour tout nettoyer sur ce composant si nécessaire
    // MessageHub.$off(); 
  }
}

Création d'un EventBus global

Pour éviter d'importer le module dans chaque composant, on peut définir une propriété globale sur le prototype de Vue en utilisant le pattern Pub/Sub.

// global-hub-setup.js
const GlobalEventHub = new Vue();

Object.defineProperty(Vue.prototype, '$hub', {
  get() {
    return GlobalEventHub;
  }
});

Une fois configuré, l'accès se fait directement via this dans n'importe quelle instance de composant :

// Émission globale
this.$hub.$emit('global-notification', { type: 'info', text: 'Sauvegarde réussie' });

// Réception globale
this.$hub.$on('global-notification', (payload) => {
  console.log(`Notification reçue: ${payload.text}`);
});

// Nettoyage
this.$hub.$off('global-notification');

Étiquettes: vuejs event-bus Component-Communication JavaScript single-page-application

Publié le 2 juillet à 23h02