Hallo Habr! Ich präsentiere Ihnen die Übersetzung des Artikels „Mastering Vuex - Zero to Hero“ von Sanath Kumar.
Die offizielle Dokumentation von Vuex definiert es als Statusverwaltungsmuster + Bibliothek für Vue.js.-Anwendungen Aber was heißt das? Was ist ein staatliches Managementmuster?
Stellen Sie sich vor, Sie arbeiten an einer großen Webanwendung mit Hunderten von Routen und Komponenten. Wäre es nicht einfacher, wenn wir alle Daten, die wir jemals in einer Anwendung benötigen würden, in einem zentralen Speicher speichern könnten?

Jede Komponente oder Route in unserer Anwendung fordert Daten aus dem Vuex-Status an und überträgt die geänderten Daten zurück in den Status.
Im Wesentlichen kann der Zustand von Vuex als die einzige Quelle der Wahrheit für die gesamte Anwendung angesehen werden.
Daten werden im Status als JSON-Objekt gespeichert. Zum Beispiel:
state: { name: "John Doe", age: "28" }
Aber wie können unsere Komponenten und Routen auf Daten zugreifen, die in unserem Bundesstaat gespeichert sind? Dazu müssen wir in unserem Vuex-Repository Getter definieren, die Daten aus dem Repository an unsere Komponenten zurückgeben. Mal sehen, wie ein einfacher Getter aussieht, der den Namen aus unserem Repository erhält:
getters: { NAME: state => { return state.name; }, }
Beachten Sie, dass der Getter-Name in Großbuchstaben geschrieben ist. Dies ist nur eine Empfehlung für den Codestil. Es ist nicht notwendig, ihm zu folgen, wenn Sie es nicht mögen.
Nachdem wir einen Getter für den Namen definiert haben, ist es unglaublich einfach, den Wert des Namens in unserer Komponente zu ermitteln. Mit dem folgenden Code können Sie dies tun.
let name = this.$store.getters.NAME;
Wir haben herausgefunden, wie Daten aus dem Speicher abgerufen werden können. Nun wollen wir sehen, wie wir die Daten im Repository festlegen können. Wir werden Setter definieren, richtig? Außerdem werden Vuex-Setter etwas anders benannt. Wir definieren eine Mutation , um Daten auf unseren Vuex-Status zu setzen.
mutations: { SET_NAME: (state, payload) => { state.name = payload; }, }
Was ist Nutzlast noch? Nutzlast sind die Daten, die von der Komponente, die die Mutation durchführt, zu unserer Mutation übertragen werden. Wie können wir das machen? Sehr einfach:
this.$store.commit('SET_NAME', your_name);
Dieser Code ändert den Status der Anwendung und legt jeden Wert fest, der Ihrem Namen für die Eigenschaft name in unserem Repository zugewiesen wurde.
MUTATIONEN SYNCHRON
Stellen Sie sich vor, wir haben eine Liste von Namen in einer Datenbank auf einem Remote-Server gespeichert. Der Server stellt uns einen Endpunkt zur Verfügung, der ein Array von Namen zurückgibt, die in unserer Vue.js verwendet werden können. Natürlich können wir Axios verwenden , um den Endpunkt abzufragen und die Daten abzurufen.
let {data} = await Axios.get('https://myapiendpoint.com/api/names');
Danach können wir das zurückgegebene Array mithilfe einer Mutation an unseren Store-Vuex-Status übergeben. Einfach, oder? Aber nicht wirklich. Mutationen sind synchron und wir können keine asynchronen Operationen wie API-Aufrufe innerhalb einer Mutation ausführen.
Was sollen wir dann tun? Aktionen erstellen.
Aktionen sind wie Mutationen, aber anstatt den Zustand direkt zu ändern, machen sie eine Mutation. Klingt verwirrend? Schauen wir uns die Ankündigung der Aktion an.
actions: { SET_NAME: (context, payload) { context.commit('SET_NAME', payload); }, }
Wir haben eine Aktion namens SET_NAME definiert, die Kontext und Nutzdaten als Parameter verwendet. Die Aktion schreibt die zuvor erstellte Mutation SET_NAME mit den an sie übergebenen Daten, dh Ihrem_Namen , fest .
Anstatt die Mutation direkt aufzurufen, lösen unsere Komponenten jetzt die Aktion SET_NAME mit einem neuen Namen als Daten wie folgt aus:
this.$store.dispatch('SET_NAME', your_name);
Dann initiiert die Aktion die Mutation mit den an sie übergebenen Daten, d. H. Ihrem_Namen .
Aber warum?
Sie fragen sich vielleicht, warum eine Aktionsdeklaration erforderlich ist, wenn wir einfach Mutationen mit einem neuen Wert direkt von unseren Komponenten aus initiieren können. Wie oben erwähnt, sind Mutationen synchron, aber keine Aktionen.
Im obigen Beispiel wird der Fall berücksichtigt, wenn Sie den Wert des Namens aktualisieren müssen, jedoch nicht nur in seinem Status, sondern auch in der Datenbank, die auf dem Remoteserver ausgeführt wird. Ich bin sicher, dass Sie Vuex in 99% der Fälle so in einem realen Projekt einsetzen möchten. Schauen Sie sich das folgende Code-Snippet an:
mutations: { SET_NAME: (state, name) => { state.name = name; }, }, actions: { SET_NAME: async (context, name) => { let {data} = await Axios.post('http://myapiendpoint.com/api/name', {name: name}); if (data.status == 200) { context.commit('SET_NAME', name); } }, }
Der Code selbst ist selbsterklärend. Wir verwenden Axios, um den Namen an den Endpunkt zu senden. Wenn die POST-Anforderung erfolgreich war und der Feldnamenwert auf dem Server erfolgreich geändert wurde, initiieren wir die SET_NAME-Mutation, um den Namenswert in unserem Status zu aktualisieren.
ÜBERNEHMEN SIE NIEMALS MUTATIONEN DIREKT. VERWENDEN SIE FÜR DIESE IMMER AKTIONEN.
Konfigurieren des Vuex-Speichers in Vue.JS
Lassen Sie uns tiefer eintauchen und herausfinden, wie wir Vuex in einer realen Anwendung implementieren können.
Schritt 1. Installieren Sie Vuex
npm install --save vuex
Schritt 2. Erstellen eines Vuex-Repositorys
- Erstellen Sie das Geschäftsverzeichnis im Stammverzeichnis unserer Anwendung.
- Erstellen Sie die Datei index.js in diesem Verzeichnis und erstellen Sie mit dem folgenden Code ein neues Repository.
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); export const store = new Vuex.Store({ state: {}, getters: {}, mutations: {}, actions: {}, });
Schritt 3. Hinzufügen von Vuex-Speicher zur Vue.JS-Anwendung
1. Importieren Sie das Repository in die Datei main.js:
import {store} from './store';
2. Fügen Sie der Vue-Instanz Speicher hinzu , wie unten gezeigt:
new Vue({ el: '#app', store, router, render: h => h(App), });
Jetzt können wir unserem Vuex-Repository Statusvariablen, Getter, Mutationen und Aktionen hinzufügen.
Beispiel
Schauen Sie sich das Vuex-Repository einer einfachen Aufgabenlistenanwendung an. "Nicht nur eine andere To-Do-Liste !!!". Huh? Keine Sorge. Am Ende dieses Artikels erfahren Sie, wie Sie die volle Leistung von Vuex nutzen können.
import Vue from 'vue'; import Vuex from 'vuex'; import Axios from 'axios'; Vue.use(Vuex); export const store = new Vuex.Store({ state: { todos: null, }, getters: { TODOS: state => { return state.todos; }, }, mutations: { SET_TODO: (state, payload) => { state.todos = payload; }, ADD_TODO: (state, payload) => { state.todos.push(payload); }, }, actions: { GET_TODO: async (context, payload) => { let {data} = await Axios.get('http://yourwebsite.com/api/todo'); context.commit('SET_TODO', data); }, SAVE_TODO: async (context, payload) => { let {data} = await Axios.post('http://yourwebsite.com/api/todo'); context.commit('ADD_TODO', payload); }, }, });
Fügen Sie der Aufgabenliste ein neues Element hinzu
Initiieren Sie in Ihrer Komponente die Aktion SAVE_TODO, indem Sie ihr ein neues Aufgabenelement übergeben, wie im folgenden Codeausschnitt gezeigt.
let item = 'Get groceries'; this.$store.dispatch('SAVE_TODO', item);
Die Aktion SAVE_TODO sendet eine POST-Anforderung an den Endpunkt und initiiert dann die ADD_TODO-Mutation , die der Statusvariablen todos ein Aufgabenelement hinzufügt.
Aufgaben erledigen
Initiieren Sie im Mounted () -Block Ihrer Komponente die zweite GET_TODO- Aktion, die alle Aufgaben vom Endpunkt empfängt und in der Statusvariablen todos speichert, wodurch die SET_TODO-Mutation initiiert wird:
mounted() { this.$store.dispatch('GET_TODO'); }
Zugriff auf Aufgaben innerhalb einer Komponente
Erstellen Sie eine berechnete Eigenschaft, um auf das todos- Element innerhalb einer Komponente zuzugreifen:
computed: { todoList() { return this.$store.getters.TODOS; }, }
Innerhalb der Komponente können Sie auf die berechnete Eigenschaft zugreifen:
<div class="todo-item" v-for="item in todoList"></div>
Verwenden der mapGetters-Methode
Mit der von Vuex bereitgestellten mapGetters- Methode können Sie noch einfacher auf Aufgaben innerhalb einer Komponente zugreifen.
import {mapGetters} from 'vuex'; computed : { ...mapGetters(['TODOS']), // }
Möglicherweise haben Sie bereits vermutet, dass der Code in der Vorlage geändert werden sollte, wie im folgenden Snippet gezeigt.
<div class="todo-item" v-for="item in TODOS"></div>
Beachten Sie, wie wir den ES6-Verteilungsoperator [...] in unseren berechneten Eigenschaften verwendet haben.
VUEX STORAGE IST NICHT NUR DIE QUELLE DES AKTUELLEN STAATS IHRER ANWENDUNG. Es ist auch der einzige Punkt, der diesen Zustand ändern sollte.
Dies bedarf einer kleinen Erklärung. Wir haben bereits gelernt, wie Sie Aktionen zum Empfangen und Installieren von Aufgaben in unserem Repository erstellen. Was ist, wenn wir ein Element aktualisieren und markieren müssen? Wo führen wir den Code dafür aus?
Im Internet finden Sie unterschiedliche Meinungen zu diesem Thema. Der Dokumentation fehlen auch diesbezüglich klare Leitlinien.
Ich würde empfehlen, alle API-Aufrufe in Aktionen in Ihrem Vuex-Repository zu speichern. Daher erfolgt jede Statusänderung nur innerhalb des Repositorys, wodurch das Debuggen erleichtert und das Verständnis des Codes vereinfacht wird und das Bearbeiten des Codes erleichtert wird.
Code Organisation
Das Speichern aller Statusvariablen, Getter, Aktionen und Mutationen in einer Datei macht es schnell umständlich, sobald Sie mit großen Anwendungen arbeiten. Lassen Sie uns sehen, wie Sie die Speicherung in mehreren Dateien als Module organisieren können.
Erstellen Sie ein neues Verzeichnis in Ihrem Repository und nennen Sie es Module . Fügen Sie die Datei todos.js dem erstellten Verzeichnis hinzu, das den folgenden Code enthält:
const state = {}; const getters = {}; const mutations = {}; const actions = {}; export default { state, getters, mutations, actions, };
Jetzt können wir die Statusvariablen, Getter, Mutationen und Aktionen aus der Datei index.js in die Datei todos.js verschieben . Denken Sie daran, Axios zu importieren. Wir müssen Vuex lediglich mitteilen, dass wir das Speichermodul erstellt haben und wo es zu finden ist. Die aktualisierte Datei index.js sollte ungefähr so aussehen:
import Vue from 'vue'; import Vuex from 'vuex'; import Axios from 'axios'; import todos from './modules/todos'; Vue.use(Vuex); export const store = new Vuex.Store({ state: {}, getters: {}, mutations: {}, actions: {}, modules: { todos, }, });
Die Datei todos.js sieht folgendermaßen aus:
import Axios from 'axios'; state = { todos: null, }; getters = { TODOS: state => { return state.todos; }, }; mutations = { SET_TODO: (state, payload) => { state.todos = payload; }, ADD_TODO: (state, payload) => { state.todos.push(payload); }, }; actions = { GET_TODO: async (context, payload) => { let {data} = await Axios.get('http://yourwebsite.com/api/todo'); context.commit('SET_TODO', data); }, SAVE_TODO: async (context, payload) => { let {data} = await Axios.post('http://yourwebsite.com/api/todo'); context.commit('ADD_TODO', payload); }, }; export default { state, getters, mutations, actions, };
Zusammenfassung
- Der Anwendungsstatus wird als ein großes JSON-Objekt gespeichert.
- Getter werden verwendet, um auf im Speicher gespeicherte Werte zuzugreifen.
- Mutationen aktualisieren Ihren Zustand. Es ist zu beachten, dass Mutationen synchron sind.
- Alle asynchronen Operationen müssen innerhalb von Aktionen ausgeführt werden . Aktionen ändern den Zustand und lösen Mutationen aus.
- Machen Sie es sich zur Regel, Mutationen ausschließlich durch Aktion auszulösen .
- Module können verwendet werden, um Ihren Speicher in mehreren kleinen Dateien zu organisieren.
Vuex macht die Arbeit mit Vue viel einfacher und macht mehr Spaß. Wenn Sie ein Anfänger sind, kann es Situationen geben, in denen es für Sie schwierig ist, zu entscheiden, ob Sie Vuex in bestimmten Bereichen Ihrer Anwendung verwenden möchten. Folge deinem Instinkt. Sie werden ziemlich schnell hohe Geschwindigkeit erreichen.