web-dev-qa-db-de.com

Kann ich von einer Mutation im Vuex-Store aus ein Commit aufrufen

Ich habe einen vuex store wie folgt:

import spreeApi from '../../gateways/spree-api'
// initial state
const state = {
  products: [],
  categories: []
}

// mutations
const mutations = {
 SET_PRODUCTS: (state, response) => {
   state.products = response.data.products
   commit('SET_CATEGORIES')
 },
 SET_CATEGORIES: (state) => {
   state.categories = state.products.map(function(product) { return product.category})
 }

}

const actions = {
 FETCH_PRODUCTS: (state, filters) => {
   return spreeApi.get('products').then(response => state.commit('SET_PRODUCTS', response))
 }
}

export default {
  state,
  mutations,
  actions
}

Ich möchte Mutation aufrufen: SET_CATEGORIES von Mutation: SET_PRODUCTS, aber das gibt mir einen Fehler: 

projectFilter.js: 22 Nicht erfasst (im Versprechen) ReferenceError: Commit ist nicht definiert (…)

Was sollte der richtige Weg sein, um dies zu tun. Ich habe store.commit und this.commit ausprobiert, aber diese haben auch ähnliche Fehler ergeben.

36
Saurabh

Wenn Sie bereits eine Mutation durchführen, gibt es keine Möglichkeit, eine andere Mutation zu commit. Eine Mutation ist ein synchroner Aufruf, der den Status ändert. Innerhalb einer Mutation können Sie keine weitere Mutation festlegen.

Hier ist die API-Referenz für Vuex: https://vuex.vuejs.org/de/api.html

Wie Sie sehen, erhält ein Mutationshandler nur state und payload, nichts weiter. Daher erhalten Sie commit als undefined.

In Ihrem obigen Fall können Sie PRODUCT und CATEGORIES als Teil desselben Mutationshandlers als Single-Commit festlegen. Sie können versuchen, wenn der folgende Code funktioniert:

// mutations
const mutations = {
    SET_PRODUCTS_AND_CATEGORIES: (state, response) => {
        state.products = response.data.products
        state.categories = state.products.map(function(product) { return product.category})
    },
    // ...
}

EDIT: Bitte beachten Sie die Antwort von Daniel S. Deboer. Die korrekte Methode besteht darin, zwei Mutationen aus einer einzigen Aktion festzulegen, wie in seiner Antwort beschrieben.

24
Mani

Wenn Sie unbedingt zwei Mutationen ausführen müssen, warum tun Sie es nicht aus einer Aktion? Aktionen müssen keine asynchronen Vorgänge ausführen. Sie können die Festschreibungsmethode in Ihrer Aktion auf die gleiche Weise wie mit state zerstören:

commitTwoThings: ({commit}, payload) => {
  commit('MUTATION_1', payload.thing)
  commit('MUTATION_2', payload.otherThing)
}
52

Um Code zwischen Mutationen gemeinsam zu nutzen, müssen Sie eine neue Funktion erstellen, die die Arbeit ausführt, die Sie dann wiederverwenden können. Glücklicherweise sind Mutationen nur alte Funktionen, und wir können den state-Parameter beliebig herumgeben, so dass dies ziemlich einfach ist.

Zum Beispiel:

const mutations = {
 SET_PRODUCTS: (state, response) => {
   state.products = response.data.products
   setCategories(state)
 },
 SET_CATEGORIES: (state) => {
   setCategories(state)
 }
}

function setCategories(state) {
  state.categories = state.products.map(product => product.category)
}
17

Und wenn ich einen allgemeinen Code habe, der den Zustand zwischen mehreren Mutationen beeinflusst, muss ich den gleichen Code auf allen meinen Mutationen duplizieren? Oder gibt es einen besseren Weg, das zu tun?

8
Nacho

Wenn Sie die Vuex-Dokumentation über Aktionen lesen, ist es ganz klar, wozu sie gemacht wurden.

  • mutationen begehen, statt den Staat zu mutieren
  • kann beliebige asynchrone Operationen enthalten

Die Aktionen can (nicht must) enthalten asynchronen Code. Tatsächlich ist das folgende Beispiel korrekt 

increment (context) {
   context.commit('increment')
}

Ich sehe kein Problem bei der Verwendung von Aktionen zum Durchführen mehrerer Mutationen.

3
Wanny Miarelli

In Ihrem Fall sollten Sie nur eine Mutation in Betracht ziehen, nämlich SET_PRODUCTS.

// mutations
const mutations = {
 SET_PRODUCTS: (state, response) => {
   state.products = response.data.products
   state.categories = state.products.map(function(product) { return product.category})
 }
}

Sie sollten SET_CATEGORIES niemals separat aufrufen. Denk darüber nach! Kategorien können nur dann geändert werden, wenn Produkte geändert werden. Und Produkte können nur durch SET_PRODUCTS geändert werden.

2
jiv-e

Edit: Ich bin auf ein sehr ähnliches Problem gestoßen und die Lösung für mich war, einen Vuex-Getter zu verwenden: https://vuex.vuejs.org/de/getters.html
Ihre Kategorien sind tatsächlich eine "berechnete" Version Ihrer Produkte. Wenn Sie Kategorien als Getter verwenden, können Sie sie mit Produkten synchronisieren und vermeiden, dass die Daten in Ihrem Geschäft dupliziert werden.

Zur Beantwortung der Frage im Titel hinterlasse ich meine ursprüngliche Antwort.
Eine Alternative zur Lösung von Daniel Buckmaster:

const mutations = {
 SET_PRODUCTS: (state, response) => {
   state.products = response.data.products
   this.SET_CATEGORIES(state)
 },
 SET_CATEGORIES: (state) => {
   state.categories = state.products.map(product => product.category)
 }
}

Wie Sie sehen, können Sie die Mutation direkt aufrufen. (wie Daniel gesagt hat, sind sie doch nur normale Funktionen)
Ich glaube, dass dies eine angemessenere Antwort auf die ursprüngliche Frage ist: Es ist eine tatsächliche Art, Mutationen ohne Code-Duplizierung oder zusätzliche Funktionen zu erstellen

0
Guillaume Meral

Für das Protokoll. Um andere Mutationen aus einer Mutationsmethode aufzurufen, gehen Sie folgendermaßen vor:

const mutations = {
    mutationOne(state, payload){
        this.commit("mutationTwo", payload)
    },
    mutationTwo(state, payload){
        console.log("called form another mutation", payload)
    }
}
0
import spreeApi from '../../gateways/spree-api'
// initial state
const state = {
  products: [],
  categories: []
}

// mutations
const mutations = {
 SET_PRODUCTS: (state, {response,commit}) => { // here you destructure the object passed to the mutation to get the response and also the commit function
   state.products = response.data.products
   commit('SET_CATEGORIES') // now the commit function is available
 },
 SET_CATEGORIES: (state) => {
   state.categories = state.products.map(function(product) { return product.category})
 }

}

const actions = {
 FETCH_PRODUCTS: ({commit}, filters) => { // here you destructure the state to get the commit function
   return spreeApi.get('products').then(response => commit('SET_PRODUCTS', {response,commit})) // here you pass the commit function through an object to 'SET_PRODUCTS' mutation
 }
}

export default {
  state,
  mutations,
  actions
}

Dies sollte es beheben. Sie können das Commit aus Ihrer Aktion in Ihre Mutation einfügen, damit Sie aus Ihrer Mutation ein Commit ausführen können. Hoffe das hilft

0
Andrei