Was wird die neue Version von Vuex sein?

Vuex ist ein Statusmanager fĂŒr Vue-Anwendungen. Die nĂ€chste Version ist Vuex 4, die fast zur offiziellen Veröffentlichung bereit ist. Es wird UnterstĂŒtzung fĂŒr Vue 3 hinzufĂŒgen, aber keine neuen Funktionen bringen.



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.



All Articles