Obwohl Vuex als groĂartige Lösung angesehen wird und viele Entwickler es als primĂ€re Statusverwaltungsbibliothek auswĂ€hlen, hoffen sie, in zukĂŒnftigen Versionen mehr Funktionen zu erhalten. WĂ€hrend sich Vuex 4 gerade auf die Veröffentlichung vorbereitet, teilt einer seiner Entwickler, Kia King Ishii (Teil des Kernteams), bereits PlĂ€ne fĂŒr die nĂ€chste Version 5. Es ist erwĂ€hnenswert, dass dies nur PlĂ€ne sind und einige Dinge sich Ă€ndern können, dennoch wurde die Hauptrichtung bereits gewĂ€hlt. Ăber ihn wird diskutiert.
Mit dem Aufkommen von Vue 3 und der Composition API begannen Entwickler, einfache Alternativen zu erstellen. Der Artikel âSie brauchen wahrscheinlich kein Vuex â zeigt beispielsweise eine einfache, flexible und zuverlĂ€ssige Möglichkeit, Composition API-basierte Stores in Verbindung mit zu erstellen
provide/inject
. Wir können davon ausgehen, dass diese und einige andere Alternativen fĂŒr kleine Anwendungen in Ordnung sind, aber wie so oft haben sie ihre Nachteile: Dokumentation, Community, Namenskonvention, Integration, Entwicklertools.
Der letzte Punkt ist sehr wichtig. Vue hat jetzt eine groĂartige Browser-ErweiterungUnterstĂŒtzung bei der Entwicklung und beim Debuggen. Das Wegwerfen kann eine groĂe Verschwendung sein, insbesondere beim Erstellen groĂer Anwendungen. GlĂŒcklicherweise wird dies mit Vuex 5 nicht passieren. Die alternativen AnsĂ€tze werden funktionieren, aber sie werden nicht so viele Vorteile bringen wie die offizielle Lösung. Lassen Sie uns daher sehen, welche Vorteile sie uns versprechen.
Ein GeschÀft erstellen
Bevor wir etwas mit der Seite machen, mĂŒssen wir es erstellen. In Vuex 4 sieht es so aus:
import { createStore } from 'vuex'
export const counterStore = createStore({
state: {
count: 0
},
getters: {
double (state) {
return state.count * 2
}
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
Der Speicher besteht auch aus 4 Teilen: Status, in dem Daten gespeichert werden; Getter, die berechnete ZustĂ€nde liefern; Mutationen, die erforderlich sind, um den Status zu Ă€ndern, und Aktionen, die auĂerhalb des GeschĂ€fts aufgerufen werden, um Operationen daran auszufĂŒhren. Normalerweise verursachen Aktionen nicht nur Mutationen (wie im Beispiel), sondern werden auch verwendet, um asynchrone Aufgaben auszufĂŒhren (da Mutationen synchron sein mĂŒssen ) oder um eine komplexere Logik zu implementieren. Wie wird Vuex 5 aussehen?
import { defineStore } from 'vuex'
export const counterStore = defineStore({
name: 'counter',
state() {
return { count: 0 }
},
getters: {
double () {
return this.count * 2
}
},
actions: {
increment () {
this.count++
}
}
})
Das erste, was sich geÀndert hat, ist die Umbenennung
createStore
in
defineStore
. Wenig spÀter wird klar, warum. Als nÀchstes gab es einen Parameter
name
zum Festlegen des Namens des GeschĂ€fts. Zuvor haben wir die Seiten in Module unterteilt, und die Modulnamen hatten die Form benannter Objekte. DarĂŒber hinaus wurden die Module im globalen Raum registriert, weshalb sie nicht autark und zur Wiederverwendung bereit waren. Als Lösung musste ein Parameter verwendet werden
namespaced
, um zu verhindern, dass mehrere Module auf dieselbe Art von Mutationen und Aktionen reagieren. Ich denke, viele sind darauf gestoĂen, aber ich werde trotzdem einen Link zur Dokumentation hinzufĂŒgen. Jetzt haben wir keine Module mehr, jeder Speicher ist standardmĂ€Ăig ein separater und unabhĂ€ngiger Speicher.
Nachdem wir den Namen angegeben haben, mĂŒssen wir ihn zu einer
state
Funktion machen, die den Anfangszustand zurĂŒckgibt und nicht nur festlegt. Dies ist sehr Ă€hnlich zu dem, wie es
data
in Komponenten aussieht . Die Ănderungen betrafen auch Getter, anstatt
state
eine Funktion als Parameter
this
fĂŒr den Zugriff auf Daten zu verwenden. Der gleiche Ansatz wird auf Aktionen
this
anstatt
stat
als Parameter angewendet . SchlieĂlich und vor allem werden Mutationen mit Actionspielen kombiniert. Kia feiertedass Mutationen ziemlich oft zu einfachen Setzern werden, was sie wortreich macht, anscheinend war dies der Grund fĂŒr die Löschung. Er erwĂ€hnt nicht, ob es möglich sein wird, StatusĂ€nderungen auĂerhalb des GeschĂ€fts vorzunehmen, beispielsweise von Komponenten. Hier können wir uns nur auf das Flussmuster beziehen, das dies nicht empfiehlt und einen zustandsverĂ€ndernden Ansatz von Aktionen fördert.
Nachtrag: Diejenigen, die die Kompositions-API zum Erstellen von Komponenten verwenden, werden froh sein zu wissen, dass es eine Möglichkeit gibt, ein GeschÀft auf Àhnliche Weise zu erstellen.
import { ref, computed } from 'vue'
import { defineStore } from 'vuex'
export const counterStore = defineStore('counter', () => {
const count = ref(0)
const double = computed(() => count.value * 2)
function increment () {
count.value++
}
return { count, double, increment }
})
Im obigen Beispiel haben wir den GeschĂ€ftsnamen als erstes Argument ĂŒbergeben
defineStore
. Der Rest ist die ĂŒbliche Kompositions-API, und das Ergebnis ist genau das gleiche wie im Beispiel mit der klassischen API.
Initialisierung speichern
Hier erwarten uns bedeutende VerĂ€nderungen. Um zu beschreiben, wie die Initialisierung des GeschĂ€fts in der 5. Version erfolgen wird, sehen wir uns an, wie dies in der 4. Version geschieht. Wenn wir ein GeschĂ€ft ĂŒber erstellen
createStore
, initialisieren wir es sofort, damit wir es dann in
app.use
oder direkt verwenden können.
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
const app = createApp(App)
app.use(store)
app.mount('#app')
// `this.$store`
// `useStore()` Composition API
import store from './store'
store.state.count // -> 0
store.commit('increment')
store.dispatch('increment')
store.getters.double // -> 4
In der 5. Version greifen wir separat auf jede Vuex-Instanz zu, was die UnabhÀngigkeit garantiert. Daher sieht dieser Prozess anders aus:
import { createApp } from 'vue'
import { createVuex } from 'vuex'
import App from './App.vue'
const app = createApp(App)
const vuex = createVuex()
app.use(vuex)
app.mount('#app')
Alle Komponenten können jetzt direkt auf jede Vuex-Instanz zugreifen, anstatt auf den globalen Bereich zuzugreifen. Schauen Sie sich ein Beispiel an:
import { defineComponent } from 'vue'
import store from './store'
export default defineComponent({
name: 'App',
computed: {
counter () {
return this.$vuex.store(store)
}
}
})
Der Anruf
$vuex.store
erstellt und initialisiert den Speicher (denken Sie an das Umbenennen
createStore
). Jedes Mal, wenn Sie ĂŒber dieses Repository kommunizieren
$vuex.store
, wird Ihnen eine bereits erstellte Instanz zurĂŒckgegeben. Im Beispiel
this.counter
können wir dies im Code weiter verwenden. Sie können den Shop auch ĂŒber initialisieren
createVuex()
.
Und natĂŒrlich eine Option fĂŒr die Composition API, wo stattdessen
$vuex.store
verwendet wird
useStore
.
import { defineComponent } from 'vue'
import { useStore } from 'vuex'
import store from './store'
export default defineComponent({
setup () {
const counter = useStore(store)
return { counter }
}
})
Der oben beschriebene Ansatz (Initialisieren des Speichers durch Komponenten) hat sowohl Vor- als auch Nachteile. Dies ist zum einen die Trennung des Codes und die Möglichkeit, ihn nur bei Bedarf hinzuzufĂŒgen. Auf der anderen Seite HinzufĂŒgen einer AbhĂ€ngigkeit (jetzt mĂŒssen Sie den Speicher jedes Mal importieren, wenn Sie ihn verwenden möchten). Wenn Sie DI verwenden möchten, können Sie daher Folgendes verwenden
provide
:
import { createApp } from 'vue'
import { createVuex } from 'vuex'
import App from './App.vue'
import store from './store'
const app = createApp(App)
const vuex = createVuex()
app.use(vuex)
app.provide('name', store)
app.mount('#app')
Und dann werfen Sie den Speicher in die Komponente (es besteht der Wunsch, ihn
name
durch eine Konstante zu ersetzen und bereits zu verwenden):
import { defineComponent } from 'vue'
export default defineComponent({
name: 'App',
inject: ['name']
})
// Composition API
import { defineComponent, inject } from 'vue'
export default defineComponent({
setup () {
const store = inject('name')
return { store }
}
})
Diese Lösung ist nicht sehr aufregend, sieht jedoch expliziter und flexibler aus als der derzeitige Ansatz. Gleiches gilt nicht fĂŒr die weitere Verwendung. Jetzt sieht es so aus:
store.state.count // State
store.getters.double // Getters
store.commit('increment') // Mutations
store.dispatch('increment') // Actions
Die neue Version wird voraussichtlich:
store.count // State
store.double // Getters
store.increment() // Actions
Alle EntitĂ€ten (Status, Getter und Aktionen) sind direkt verfĂŒgbar, was die Arbeit mit ihnen einfacher und logischer macht. Zur gleichen Zeit entfernt es die Notwendigkeit
mapState
,
mapGetters
,
mapActions
und
mapMutations
sowie das Schreiben zusÀtzliche berechnete Eigenschaften.
Teilen
Der letzte zu berĂŒcksichtigende Punkt ist das Teilen. Wir erinnern uns, dass wir in Vuex 5 keine benannten Module mehr haben und jede Seite separat und unabhĂ€ngig ist. Dies ermöglicht es, sie bei Bedarf zu importieren und die Daten wie Komponenten nach Bedarf zu verwenden. Es stellt sich eine logische Frage, wie mehrere GeschĂ€fte zusammen verwendet werden können. In Version 4 gibt es immer noch einen globalen Namespace, und wir mĂŒssen verschiedene Speicher in diesem Bereich verwenden
rootGetters
und
rootState
darauf verweisen (genau wie in Version 3). Der Ansatz in Vuex 5 ist anders:
// store/greeter.js
import { defineStore } from 'vuex'
export default defineStore({
name: 'greeter',
state () {
return { greeting: 'Hello' }
}
})
// store/counter.js
import { defineStore } from 'vuex'
import greeterStore from './greeter'
export default defineStore({
name: 'counter',
use () {
return { greeter: greeterStore }
},
state () {
return { count: 0 }
},
getters: {
greetingCount () {
return `${this.greeter.greeting} ${this.count}'
}
}
})
Wir importieren das GeschÀft, registrieren es dann bei
use
und greifen darauf zu. Alles sieht noch einfacher aus, wenn Sie die Kompositions-API verwenden:
// store/counter.js
import { ref, computed } from 'vue'
import { defineStore } from 'vuex'
import greeterStore from './greeter'
export default defineStore('counter', ({use}) => {
const greeter = use(greeterStore)
const count = 0
const greetingCount = computed(() => {
return `${greeter.greeting} ${this.count}`
})
return { count, greetingCount }
})
ErwÀhnenswert ist nur, dass es
use
genauso funktioniert
vuex.store
und fĂŒr die korrekte Initialisierung der Filialen verantwortlich ist.
TypeScript-UnterstĂŒtzung
Mit API-Ănderungen und weniger Abstraktionen wird die TypeScript-UnterstĂŒtzung in Version 4 viel besser sein, aber wir benötigen noch viel manuelle Arbeit. Mit der Veröffentlichung von Version 5 können Typen hinzugefĂŒgt werden, wo dies erforderlich ist und wo wir es möchten.
Fazit
Vuex 5 sieht vielversprechend aus und ist genau das, was viele erwarten (Beheben alter Fehler, HinzufĂŒgen von FlexibilitĂ€t). Eine vollstĂ€ndige Liste der Diskussionen und Ansichten des Kernteams finden Sie im Vue RFCs- Repository.