Can I call commit from one of mutations in Vuex store

后端 未结 12 1090
醉酒成梦
醉酒成梦 2021-02-03 16:25

I have a vuex store, like following:

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

// mu         


        
相关标签:
12条回答
  • 2021-02-03 17:21

    In your case you should consider having only one mutation, namely SET_PRODUCTS.

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

    You should never have any need to call SET_CATEGORIES separately. Think about it! Categories can only mutate if products are changed. And products can change only through SET_PRODUCTS.

    0 讨论(0)
  • 2021-02-03 17:22

    For the record. To call other mutations from a mutation method do it like this:

    const mutations = {
        mutationOne(state, payload){
            this.commit("mutationTwo", payload)
        },
        mutationTwo(state, payload){
            console.log("called from another mutation", payload)
        }
    }
    
    0 讨论(0)
  • 2021-02-03 17:22

    To share code between mutations, you must create a new function that performs the work, which you can then reuse. Fortunately, mutations are just plain old functions, and we can pass the state parameter around however we like, so this is quite easy to do.

    For example:

    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)
    }
    
    0 讨论(0)
  • 2021-02-03 17:25

    When you are already doing a mutation, there is no way to commit another mutation. A mutation is a synchronous call which changes the state. Within one mutation, you will not be able to commit another mutation.

    Here is the API reference for Vuex: https://vuex.vuejs.org/en/api.html

    As you can see, a mutation handler receives only state and payload, nothing more. Therefore you are getting commit as undefined.

    In your case above, you can set the PRODUCT and CATEGORIES as part of the same mutation handler as a single commit. You can try if the following code works:

    // 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: Please refer to the answer below, provided by Daniel S. Deboer. The correct method is to commit two mutations from a single action, as described in his answer.

    0 讨论(0)
  • 2021-02-03 17:25

    Edit : I stumbled upon a very similar problem and the solution for me was to use a vuex getter : https://vuex.vuejs.org/en/getters.html
    Your categories is actually a "computed" version of your products. Having categories as a getter allows you to keep them in sync with products and avoids duplicating the data in your store.

    For the sake of answering the question in the title i leave my original answer.
    An alternative to Daniel Buckmaster solution :

    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)
     }
    }
    

    As you can see you could directly call the mutation itself. (as Daniel said, they are just plain functions after all)
    I believe that this is a more appropriate answer to the original question : it is an actual way of composing mutations without code duplication or extra functions

    0 讨论(0)
  • 2021-02-03 17:27

    I prefer to call mutations.SET_CATEGORIES(state) instead of: - calling 2 different commits from an artificial action - or doing commit() inside a mutation as it makes unit testing more difficult.

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

    My opinion is that you don't need to see SET_CATEGORIES in the VueToolbox. The time travel should work anyways. Please, correct me if I'm wrong.

    0 讨论(0)
提交回复
热议问题