Verwendung eines Event-Bus zum Teilen von Props zwischen Vue Komponenten

Avatar of Kingsley Silas
Von Kingsley Silas am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Standardmäßig erfolgt die Kommunikation zwischen Vue-Komponenten über Props. Props sind Eigenschaften, die von einer Elternkomponente an eine Kindkomponente weitergegeben werden. Hier ist zum Beispiel eine Komponente, bei der title eine Prop ist.

<blog-post title="My journey with Vue"></blog-post>

Props werden immer von der Elternkomponente an die Kindkomponente übergeben. Wenn Ihre Anwendung komplexer wird, stoßen Sie langsam auf das, was als Prop-Drilling bezeichnet wird. Hier ist ein verwandter Artikel, der auf React ausgerichtet ist, aber durchaus zutreffend ist). Prop-Drilling ist die Idee, Props nach unten und nach unten und nach unten an Kindkomponenten weiterzugeben – und, wie Sie sich vorstellen können, ist dies im Allgemeinen ein mühsamer Prozess.

Mühsames Prop-Drilling kann also ein potenzielles Problem in einer komplexen Anwendung sein. Das andere hat mit der Kommunikation zwischen *unabhängigen* Komponenten zu tun. Wir können all dies durch die Nutzung eines Event-Bus lösen.

Was ist ein Event-Bus? Nun, das steckt schon im Namen. Es ist eine Art Transportmittel für eine Komponente, um Props von einer Komponente an eine andere zu übergeben, egal wo sich diese Komponenten im Baum befinden.

Übungsaufgabe: Einen Zähler bauen

Lassen Sie uns gemeinsam etwas bauen, um das Konzept eines Event-Bus zu demonstrieren. Ein Zähler, der einen eingegebenen Wert addiert oder subtrahiert und die Gesamtsumme tallyt, ist ein guter Ausgangspunkt.

Sehen Sie den Pen Vuejs Event Bus Counter von Kingsley Silas Chijioke (@kinsomicrote) auf CodePen.

Um einen Event-Bus zu nutzen, müssen wir ihn zuerst wie folgt initialisieren:

import Vue from 'vue';
const eventBus = new Vue();

Dies setzt eine Instanz von Vue auf eventBus. Sie können es beliebig benennen. Wenn Sie eine Single-File-Komponente verwenden, sollten Sie diesen Snippet in einer separaten Datei ablegen, da Sie die Vue-Instanz, die eventBus zugewiesen ist, ohnehin exportieren müssen.

import Vue from 'vue';
export const eventBus = new Vue();

Wenn das erledigt ist, können wir ihn in unserer Zählerkomponente verwenden.

Hier ist, was wir tun wollen:

  • Wir möchten eine Zählung mit einem Anfangswert von 0 haben.
  • Wir möchten ein Eingabefeld, das numerische Werte akzeptiert.
  • Wir möchten zwei Schaltflächen: eine, die den eingegebenen numerischen Wert beim Klicken zur Zählung hinzufügt, und die andere, die diesen eingegebenen numerischen Wert von der Zählung subtrahiert, wenn sie geklickt wird.
  • Wir möchten eine Bestätigung dessen, was passiert ist, wenn sich die Zählung ändert.

So sieht die Vorlage mit all diesen Elementen aus:

<div id="app">
  <h2>Counter</h2>
  <h2>{{ count }}</h2>
  <input type="number" v-model="entry" />
  <div class="div__buttons">
    <button class="incrementButton" @click.prevent="handleIncrement">
      Increment
    </button>
    <button class="decrementButton" @click.prevent="handleDecrement">
      Decrement
    </button>
  </div>
  <p>{{ text }}</p>
</div>

Wir binden das Eingabefeld an einen Wert namens entry, den wir verwenden werden, um die Zählung entweder zu erhöhen oder zu verringern, je nachdem, was der Benutzer eingibt. Wenn eine der Schaltflächen geklickt wird, lösen wir eine Methode aus, die den Wert von count entweder erhöhen oder verringern sollte. Schließlich ist dieses {{ text }}-Ding im <p>-Tag die Nachricht, die wir ausgeben, um die Änderung der Zählung zusammenzufassen.

So fügt sich das alles in unserem Skript zusammen:

new Vue({
  el: '#app',
  data() {
    return {
      count: 0,
      text: '',
      entry: 0
    }
  },
  created() {
    eventBus.$on('count-incremented', () => {
      this.text = `Count was increased`
      setTimeout(() => {
        this.text = '';
      }, 3000);
    })
    eventBus.$on('count-decremented', () => {
      this.text = `Count was decreased`
      setTimeout(() => {
        this.text = '';
      }, 3000);
    })
  },
  methods: {
    handleIncrement() {
      this.count += parseInt(this.entry, 10);
      eventBus.$emit('count-incremented')
      this.entry = 0;
    },
    handleDecrement() {
      this.count -= parseInt(this.entry, 10);
      eventBus.$emit('count-decremented')
      this.entry = 0;
    }
  }
})

Sie haben vielleicht bemerkt, dass wir uns mit diesem Code auf den Event-Bus begeben.

Als Erstes müssen wir einen Pfad einrichten, um ein Ereignis von einer Komponente an eine andere zu senden. Diesen Pfad können wir mit eventBus.$emit() (wobei "emit" ein schickes Wort für das Aussenden ist) ebnen. Dieses Aussenden ist in zwei Methoden enthalten, handleIncrement und handleDecrement, die auf die Eingabeübermittlungen reagieren. Und sobald diese passieren, rastet unser Event-Bus zu jeder Komponente, die Daten anfordert, und sendet die Props über.

Sie haben vielleicht bemerkt, dass wir beide Ereignisse im created()-Lifecycle-Hook mit eventBus.$on() abhören. Bei beiden Ereignissen müssen wir den String übergeben, der dem emittierten Ereignis entspricht. Dies ist wie eine Kennung für das jeweilige Ereignis und das, was eine Möglichkeit für eine Komponente schafft, Daten zu empfangen. Wenn eventBus ein bestimmtes angekündigtes Ereignis erkennt, wird die folgende Funktion aufgerufen – und wir setzen einen Text, um anzuzeigen, was passiert ist, und lassen ihn nach drei Sekunden verschwinden.

Übungsaufgabe: Mehrere Komponenten verwalten

Nehmen wir an, wir arbeiten an einer Profilseite, auf der Benutzer ihren Namen und ihre E-Mail-Adresse für eine App aktualisieren und die Aktualisierung dann sehen können, ohne die Seite neu laden zu müssen. Dies kann reibungslos mit einem Event-Bus erreicht werden, obwohl wir dieses Mal mit zwei Komponenten zu tun haben: dem Benutzerprofil und dem Formular, das die Profiländerungen übermittelt.

Sehen Sie den Pen Vuejs Event Bus 2 von Kingsley Silas Chijioke (@kinsomicrote) auf CodePen.

Hier ist die Vorlage:

<div class="container">
  <div id="profile">
    <h2>Profile</h2>
    <div>
      <p>Name: {{name}}</p>
      <p>Email: {{ email }}</p>
    </div>
  </div>

  <div id="edit__profile">
    <h2>Enter your details below:</h2>
    <form @submit.prevent="handleSubmit">
      <div class="form-field">
        <label>Name:</label>
        <input type="text" v-model="user.name" />
      </div>
      <div class="form-field">
        <label>Email:</label>
        <input type="text" v-model="user.email" />
      </div>
      <button>Submit</button>
    </form>
  </div>
</div>

Wir werden die ids (user.name und user.email) an die entsprechende Komponente übergeben. Zuerst richten wir die Vorlage für die Komponente "Edit Profile" (edit__profile) ein, die die Namen- und E-Mail-Daten enthält, die wir an die "Profile"-Komponente übergeben möchten, die wir als Nächstes einrichten. Wieder einmal haben wir einen Event-Bus eingerichtet, um diese Daten zu emittieren, nachdem er eine Übermittlungsereignis erkannt hat.

new Vue({
  el: "#edit__profile",
  data() {
    return {
      user: {
        name: '',
        email: ''
      }
    }
  },
  methods: {
    handleSubmit() {
      eventHub.$emit('form-submitted', this.user)
      this.user = {}
    }
  }
})

Diese Daten werden verwendet, um das Profil des Benutzers in der "Profile"-Komponente (profile) reaktiv zu aktualisieren, die auf name und email wartet, wenn der Bus an ihrem Hub ankommt.

new Vue({
  el: '#profile',
  data() {
    return {
      name: '',
      email: ''
    }
  },
  created() {
    eventHub.$on('form-submitted', ({ name, email}) => {
      this.name = name;
      this.email = email
    })
  }
})

Ihre Taschen sind gepackt. Jetzt müssen sie nur noch nach Hause gehen.

Ziemlich cool, oder? Auch wenn die Komponenten "Edit Profile" und "Profile" nicht zusammenhängen (oder keine direkte Eltern-Kind-Beziehung haben), ist es möglich, dass sie miteinander kommunizieren, verbunden durch dasselbe Ereignis.

Rollin’ right along

Ich habe Event-Bus in Fällen hilfreich gefunden, in denen ich Reaktivität in meiner App aktivieren möchte – insbesondere, um eine Komponente basierend auf der vom Server erhaltenen Antwort zu aktualisieren, ohne die Seite neu laden zu müssen. Es ist auch möglich, dass das emittierte Ereignis von mehr als einer Komponente abgehört werden kann.

Wenn Sie andere interessante Szenarien für die Verwendung eines Event-Bus haben, würde ich sie gerne in den Kommentaren erfahren. 🚌