VuejsVueX

Auf dieser Seite... (ausblenden)

  1.   1.  Vue.js
    1.   1.1  State-Management mit vuex
    2.   1.2  reststate-vuex
    3.   1.3  Setup
    4.   1.4  Auslesen
    5.   1.5  Ladefortschritt und Fehler
    6.   1.6  Anlegen von Ressourcen
    7.   1.7  Löschen von Ressourcen
    8.   1.8  Ändern von Ressourcen
    9.   1.9  Mehr

1.  Vue.js

Natürlich wollen wir die Stud.IP-JSONAPI auch gerne in Vue.js verwenden. Mit den bekannten Tools wie XMLHttpRequest und fetch bzw. mit Wrapper-Bibliotheken wie axios ist das einfach möglich. Können wir das aber noch ein bisschen praktisch nutzbarer gestalten?

Wichtig in dem Zusammenhang ist, dass Vue.js ein komponentenbasiertes Framework ist. Das generierte HTML entsteht aus mehrfach verwendbaren Komponenten, die letztlich einen Komponentenbaum bilden.

1.1  State-Management mit vuex

Ein häufig wiederkehrendes Problem in komponentenbasierten Web-Frameworks ist die Frage des State-Managements. Wie gestalte ich den Zugriff auf den „State“, die Daten, meiner Applikation. Die üblichen Ansätze, die in Vue.js verwendet werden, ist die Weitergabe von relevanten Daten von Elternkomponenten an ihre Kindkomponenten.

Ein Beispiel:

  • Zwei Komponentenknoten benötigen dieselben Daten.
  • Sie sind aber nur sehr weit entfernt miteinander verwandt, hängen also z.B. jeweils tief in zwei unterschiedlichen Hauptästen

Das führt in der Regel dazu, dass die Daten dann vom nächsten gemeinsamen Verwandten bereitgestellt und dann über die komplette Verwandtschaftslinien durchgereicht werden müssen, obwohl die dazwischen liegenden Knoten nichts mit diesen Daten zu tun haben.

An dieser Stelle hakt vuex ein und bietet einen zentralen Store an, auf den alle Komponenten zugreifen können.

Wenn wir Daten aus der JSONAPI auslesen, lohnt es sich also, diese in den Store einzuspeisen, damit es unter anderem klar definierte Punkte gibt, an denen auf die JSONAPI zugegriffen wird, um performanzproblematische Doppelungen zu verhindern.

Wir wollen also unbedingt eine Kombination von JSONAPI und vuex haben.

1.2  reststate-vuex

Zum Glück gibt es schon ein paar Bibliotheken, um JSONAPI und vuex zu verknüpfen. Für die Implementation der Courseware 5 haben wir uns für eine Bibliothek entschieden, die wir um weitere Möglichkeiten erweitert haben und gegenwärtig vom ELAN e.V. gepflegt wird:

https://github.com/elan-ev/reststate-vuex

1.3  Setup

Das Setup, um reststate-vuex zu nutzen, konfiguriert eine axios-Instanz mit unserer JSONAPI-Schnittstelle. Diesen Code sehen wir ja in der Regel nur sehr selten.

const getHttpClient = () =>
    axios.create({
        baseURL: STUDIP.URLHelper.getURL(`jsonapi.php/v1`, {}, true),
        headers: {
            'Content-Type': 'application/vnd.api+json',
        },
    });

// […]

const store = new Vuex.Store({
    modules: {
        courseware: CoursewareModule,
        ...mapResourceModules({
            names: [
                'courses',
                'courseware-blocks',
                'courseware-block-comments',
                'courseware-containers',
                'courseware-instances',
                'courseware-structural-elements',
                'courseware-user-data-fields',
                'courseware-user-progresses',
                'files',
                'file-refs',
                'folders',
                'users',
            ],
            httpClient,
        }),
    },
});

Im obigen Code machen wir u.a. die JSONAPI-Schemata "courses", "users", "files" usw. bekannt. Was können wir jetzt damit anstellen?

1.4  Auslesen

Vielleicht wollen wir gerne alle Nutzer auslesen und in einer Vue.js-Komponente ausgeben:

<template>
<div>
  <ul>
    <li v-for="user in allUsers" :key="user.id">
      {{ user.attributes['formatted-name'] }}
    </li>
  </ul>
</div>
</template>

<script>
import { mapActions, mapGetters } from 'vuex';

export default {
    name: 'users-list',
    mounted() {
        this.loadAllUsers();
    },
    methods: {
        ...mapActions({
            loadAllUsers: 'users/loadAll',
        }),
    },
    computed: {
        ...mapGetters({
            allUsers: 'users/all',
        }),
    },
};
</script>
 Das verschafft schon einen guten Überblick, was uns reststate-vuex bieten kann. Hier die wichtigsten Punkte:
  • Wir verwenden wie gewohnt mapActions und mapGetters, um Actions und Getter von reststate-vuex aufzurufen.
  • Die loadAll-Action lädt alle Daten des jeweiligen JSONAPI-Schemas und speichert diese im Store.
  • Wir verwenden den all-Getter, um alle Ressourcen eines JSONAPI-Schemas aus dem Store zu erhalten.
  • Der Zugriff auf eine user-Ressource erfolgt dann erwartungsgemäß mit user.id oder im user.attributes-Objekts.

Einzelne Ressourcen können über die Action users/loadById aus dem JSONAPI-Backend in den Store geladen und über den Getter users/byId aus dem Store geholt werden.

1.5  Ladefortschritt und Fehler

Damit wir nicht immer wieder Ladefortschritt- und Fehlerbehandlung implementieren müssen, sind nur wenige Änderungen notwendig. Zunächst ergänzen wir die vorhandenen Getter:

...mapGetters({
+      isLoading: 'users/isLoading',
+      isError: 'users/isError',
       allUsers: 'users/all',
     })

und können dann auf diese im Template zugreifen:

<template>
   <div>
-    <ul>
+    <p v-if="isLoading" v-translate>Laden...</p>
+    <p v-else-if="isError" v-translate>Fehler beim Laden.</p>
+    <ul v-else>
       <li
         v-for="user in allUsers"

1.6  Anlegen von Ressourcen

Mit reststate-vuex können wir:

  • Ressourcen im JSONAPI-Backend via axios anlegen
  • und diese natürlich auch im vuex Store zugänglich machen

Dazu ergänzen wir nur eine Action. Hier ein Beispiel für die Courseware, um Blöcke zu erstellen:

methods: {
     ...mapActions({
+      createBlock: 'courseware-blocks/create',
     }),

Diese Action können wir jetzt im JavaScript-Code verwenden:

// Der `container` stammt aus dem Store, aber das geht auch per Hand.
const container = { type: 'courseware-containers', id: '17' };

// Wir erstellen eine JSON-Repräsentation eines Courseware-Blocks:
//   - mit einem Beispiel-Block-Type.
//   - ohne `payload`
//   - mit Verknüpfung zu einem Courseware-Container
const block = {
    attributes: {
        'block-type': 'text',
        'payload': null,
    },
    relationships: {
        container: {
            data: { type: container.type, id: container.id },
        },
    },
};

this.createBlock('courseware-blocks/create', block);

1.7  Löschen von Ressourcen

Um Ressourcen im JSONAPI-Backend und im vuex-Store zu löschen, verwenden wir einfach die entsprechende Action:

methods: {
     ...mapActions({
+      deleteBlock: 'courseware-blocks/delete',
     }),

und verwenden diese Action dann einfach in unsere Vue.js-Komponente:

+ <button @click="deleteBlock(block)" v-translate>
+   Block löschen
+ </button>

1.8  Ändern von Ressourcen

Auch für das Ändern von Ressourcen im JSONAPI-Backend und im vuex-Store gibt es eine entsprechende Action:

methods: {
     ...mapActions({
+      updateBlock: 'courseware-blocks/update',
     }),

und verwenden diese Action im JavaScript-Code

const block = this.getBlock({ id: '17' });
block.attributes.payload = { foo: 'bar' };
this.updateBlock(block);

Da der vuex Store reaktiv ist, ändern sich dadurch wie gewohnt alle Komponenten, die mit dieser Ressource zusammenarbeiten und natürlich auch im JSONAPI-Backend.

1.9  Mehr

Die reststate-vuex-Bibliothek bietet noch viele andere Möglichkeiten, die von der JSONAPI angeboten werden, gut dokumentiert unter https://vuex.reststate.codingitwrong.com/

Letzte Änderung am March 05, 2021, at 01:46 PM von tgloeggl.