Komplexe Webanwendungen mit Vue.js, Teil 2

Vuex Actions und Mutations

Jede Zustandsveränderung erfolgt innerhalb einer dedizierten Funktion. Vuex nennt sie Mutations. Eine Mutations-Funktion erhält ein Zustandsobjekt und gibt es verändert zurück. Im Beispiel kann man eine weitere Programmiersprache so hinzufügen:

export default new Vuex.Store({
state: {
// ...
},
mutations: {
addLanguage (state, language) {
state.languages.push(language)
}
}
})

Mutations-Funktionen müssen immer synchron sein. Folgende Zeile löst sie mittels commit aus:

this.$store.commit("addLanguage", { name: "Kotlin", created: 2016 })

Wenn an der Veränderung ein asynchroner Aufruf beteiligt ist, kommen sogenannte Actions zum Einsatz. Anstatt den Zustand direkt zu verändern, können sie beliebige asynchrone Logik enthalten und nach deren Durchlauf eine Mutations-Funktion aufrufen:

export default new Vuex.Store({
state: {
// ...
},
mutations: {
// ...
},
actions: {
addLanguage(context, language) {
Promise.resolve().then(() => {
context.commit("addLanguage", language);
});
}
}
});

Actions können auch mehrere verschiedene Mutationsfunktionen aufrufen. In der Praxis könnte man zunächst ein Flag setzen, um eine Ladeanimation anzuzeigen, bevor der asynchrone Aufruf stattfindet. Kommt ein Ergebnis zurück, blendet die Anwendung die Animation wieder aus und verarbeitet das Ergebnis. Tritt ein Fehler auf, hinterlegt eine Mutations-Funktion den Zustand ebenfalls im Store. Actions enthalten also häufig mehrere Verarbeitungsschritte inklusive Fehlerbehandlung, und Mutationsfunktionen überführen die Änderungen am Zustand in den Store.

Der Aufruf in der Komponente sieht nun so aus:

this.$store.dispatch("addLanguage", { name: "Kotlin", created: 2016 })

Vuex in der Praxis

Vuex bietet für den Einsatz in großen Anwendungen weitere Vereinfachungen. Es gibt mehrere Hilfsfunktionen, die den Zugriff in den Komponenten auf den Store vereinfachen können, anstatt jeweils eine Computed Property anzugeben. Sie ändern jedoch nichts an der grundlegenden Funktionsweise, weshalb der Artikel nur die vollständige Schreibweise aufführt.

Für große Anwendungen ist es weiterhin sinnvoll, den State-Tree in Module zu unterteilen. Jedes Modul kapselt einen Teil des States und enthält eigene Getter, Actions und Mutations. Man kann je Modul entscheiden, ob es einen eigenen Namensraum definiert. Ohne Namensraum übernimmt der globale Store alle Inhalte, als hätte man sie dort definiert.

Zu Beginn eines Projekts sollten Entwickler den Einsatz von Vuex im Detail festlegen. Zum Beispiel ist zu entscheiden, ob der Aufruf von Mutations aus Komponenten heraus erlaubt ist oder grundsätzlich Actions verwendet werden sollen. Weiterhin ist zu entscheiden, wie mit Formularinhalten umzugehen ist.

Scheint ein Anwendungsfall nicht mit Vuex lösbar zu sein, liegt es typischerweise an einer falschen Herangehensweise. Das Flux-Pattern erfolgreich einzusetzen erfordert ein Umdenken in Bezug auf den inneren Aufbau einer Anwendung. Richtig angewendet, belohnt es Entwickler mit einer stabilen, skalierbaren und langlebigen Softwarearchitektur.