Entwickler, der außergewöhnliche CRM- und Laravel-Lösungen liefert

Als erfahrener Entwickler spezialisiere ich mich auf Laravel- und Vue.js-Entwicklung, die Implementierung von Vtiger CRM sowie auf vielfältige WordPress-Projekte. Meine Arbeit zeichnet sich durch kreative, dynamische und benutzerzentrierte Weblösungen aus, die individuell an die Bedürfnisse meiner Kunden angepasst werden.

In modernen Vue.js-Anwendungen gibt es ein sehr interessantes Konzept, das sogenannten Headless- oder Renderless-Components. Diese Komponenten trennen die reine Logik von der Darstellung, was insbesondere dann hilfreich ist, wenn komplexe Geschäftslogik – wie beispielsweise API-Anfragen – verarbeitet werden soll.

Vue.js – Einen Headless Component für die API-Arbeit erstellen

In modernen Vue.js-Anwendungen gibt es ein sehr interessantes Konzept, das sogenannten Headless- oder Renderless-Components. Diese Komponenten trennen die reine Logik von der Darstellung, was insbesondere dann hilfreich ist, wenn komplexe Geschäftslogik – wie beispielsweise API-Anfragen – verarbeitet werden soll. So bleibt die UI flexibel und wiederverwendbar, während die Komponenten, die die Geschäftslogik enthalten, an zentraler Stelle gepflegt werden.

Die Motivation

In vielen Vue.js-Projekten kommen regelmäßig Ajax-Anfragen mit Hilfe von axios zum Einsatz. Oftmals findet man sich dabei wieder – man kopiert immer wieder ähnliche Code-Stücke von einem Component zum anderen. Mixins können dabei ab und zu helfen, bergen jedoch ihre eigenen Tücken, da sie nicht immer einfach anpassbar sind, wenn sich Parameter wie Anfrage-URLs oder Request-Optionen ändern.

Headless Components helfen hier enorm weiter: Die Logik zur Ausführung und Verarbeitung von HTTP-Anfragen wird in einem separaten, speziell dafür entwickelten Component gebündelt. Dieser Component führt die Anfrage durch, verarbeitet die Antwort und übergibt die Ergebnisse an den Eltern- oder Kind-Component über sogenannte scoped Slots. Dadurch bleibt der Code sauber und wiederverwendbar.

So funktioniert eine typische axios-Anfrage

Erinnern wir uns zunächst an eine einfache axios-Anfrage:

axios.get('https://jsonplaceholder.typicode.com/posts/1')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error(error);
  });

Für das öffentliche API-Beispiel oben erwarten wir als Antwort einen JSON-Block wie:

{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}

Um beispielsweise den Titel aus der Antwort zu erhalten, greift man auf response.data.title zu.

────────────────────────────
Der Headless Request Component

Mit diesem Wissen können wir nun einen Component erstellen, dessen Aufgabe es ist, eine Anfrage an eine übergebene URL zu tätigen, den Ladezustand und die Antwortdaten zu verwalten – und das alles im Hintergrund. Im Template des Eltern-Components wird dann über einen scoped Slot festgelegt, wie die Daten dargestellt werden sollen. So könnte die Verwendung aussehen:

<request url="https://jsonplaceholder.typicode.com/posts/1">
  <template v-slot:default="{ loading, data }">
    <div v-if="loading">Loading...</div>
    <div v-else>
      <h1>{{ data.title }}</h1>
      <p>{{ data.body }}</p>
    </div>
  </template>
</request>

In diesem Beispiel übergibt der Component request über den Slot zwei wichtige Parameter:

  • loading – ein Boolescher Wert, der angibt, ob die Anfrage noch läuft
  • data – das Ergebnis der API-Anfrage (genauer: response.data)

So kann der übergeordnete Component ganz flexibel entscheiden, wie und wann ein Ladeindikator oder die tatsächlichen Inhalte angezeigt werden.

────────────────────────────
Implementierung des Request Components

Im Folgenden finden Sie ein Beispiel, wie dieser Headless Component in Vue.js implementiert werden könnte:


Vue.component("Request", {
  render() {
    return this.$scopedSlots.default({
      loading: this.loading,
      data: this.response && this.response.data
    })[0];
  },
  props: {
    url: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      loading: true,
      response: null
    };
  },
  created() {
    axios.get(this.url)
      .then(response => {
        this.response = response;
        this.loading = false;
      })
      .catch(error => {
        console.error(error);
        this.loading = false;
      });
  }
});

In diesem Component werden folgende Aufgaben übernommen:

  • Es wird über die Property url festgelegt, wohin die Anfrage gesendet wird.
  • Im Lifecycle-Hook created erfolgt die axios-Anfrage.
  • Nach erfolgreicher Ausführung wird die Antwort gespeichert und der Ladevorgang beendet.
  • Mithilfe eines scoped Slots werden dem Eltern-Component die relevanten Daten (Ladezustand und Antwortdaten) übergeben.

Bemerkenswert ist, dass dieser Component keinerlei fest vorgegebene Darstellung hat. Die gesamte UI wird im Eltern-Component definiert, wodurch ein hoher Grad an Flexibilität entsteht. Gleichzeitig kann der Component jedoch beliebig oft und an verschiedenen Stellen der Anwendung eingesetzt werden – ganz ohne die Kopie und Anpassung von Codefragmenten.

────────────────────────────
Fazit

Headless bzw. Renderless Components in Vue.js sind eine hervorragende Möglichkeit, um komplexe Logik – wie API-Anfragen mit axios – von der Darstellung zu trennen. Durch die Verwendung von scoped Slots gelingt es, den Code übersichtlich, modular und wiederverwendbar zu gestalten. Dies führt zu einer besseren Trennung von Geschäftslogik und UI, erhöht die Testbarkeit und reduziert redundante Code-Duplikationen.

Mit diesem Ansatz können Entwicklerinnen und Entwickler in ihren Vue.js-Projekten nicht nur den Überblick behalten, sondern auch im Bedarfsfall flexibel unterschiedliche Render-Varianten implementieren, ohne die zugrunde liegende Logik mehrfach pflegen zu müssen.

Happy Coding und viel Erfolg bei der Umsetzung Ihrer eigenen Headless Components!