我可以从Vuex商店中的一个突变调用commit

时间:2016-11-08 13:01:29

标签: javascript vue.js vuex

我有一个vuex商店,如下所示:

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
}

我想调用突变:SET_CATEGORIES来自变异:SET_PRODUCTS,但这给了我错误:

  

projectFilter.js:22 Uncaught(在promise中)ReferenceError:commit未定义(...)

这应该是正确的方法。我尝试了store.committhis.commit,但这些也给出了类似的错误。

13 个答案:

答案 0 :(得分:59)

如果你绝对必须提交两个突变,为什么不从一个动作做到这一点?操作不必执行异步操作。您可以像处理状态一样对动作中的提交方法进行解构:

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

答案 1 :(得分:29)

如果您已经进行了突变,则无法commit另一种突变。突变是一种改变状态的同步呼叫。在一个突变中,您将无法进行另一次突变。

以下是Vuex的API参考:https://vuex.vuejs.org/en/api.html

如您所见,变异处理程序仅接收statepayload,仅此而已。因此,您commitundefined

在上面的例子中,您可以将PRODUCT和CATEGORIES设置为与单个提交相同的变异处理程序的一部分。如果以下代码有效,您可以尝试:

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

编辑:请参阅下面的答案,由 Daniel S. Deboer 提供。正确的方法是从一个动作中提交两个突变,如他的回答所述。

答案 2 :(得分:19)

要在突变之间共享代码,您必须创建一个执行工作的新函数,然后您可以重复使用该函数。幸运的是,突变只是普通的旧函数,我们可以随意传递state参数,所以这很容易做到。

例如:

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

答案 3 :(得分:9)

如果我有一些影响多个突变之间状态的常用代码,我必须在我的所有突变上复制相同的代码?或者有更好的方法吗?

答案 4 :(得分:4)

阅读Vuex documentation on Actions,它非常清楚它们的用途。

  • 提交突变而不是改变状态
  • 可以包含任意异步操作

操作可以(不是必须)包含异步代码。实际上,以下示例是正确的

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

我没有看到使用操作执行多个突变的任何问题。

答案 5 :(得分:3)

作记录。要从突变方法中调用其他突变,请按以下步骤操作:

const mutations = {
    mutationOne(state, payload){
        this.commit("mutationTwo", payload)
    },
    mutationTwo(state, payload){
        console.log("called form another mutation", payload)
    }
}

答案 6 :(得分:2)

在您的情况下,您应该考虑只有一个突变,即SET_PRODUCTS。

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

您永远不需要单独调用SET_CATEGORIES。想一想!如果产品发生变化,类别只能改变。产品只能通过SET_PRODUCTS进行更改。

答案 7 :(得分:1)

首先,将Vue按钮分配给变量: 在main.js中:

  export const app = new Vue({  
  router,
  vuetify,
  store,....

然后将“ app”变量导入到您定义突变的js文件中: 在modules.js中:

import { app } from "../../main";

您现在可以将其用作“ app。$ store.commit”:

mutations: {
[AUTH_SET_TOKEN]: () => {
app.$store.commit(USER_SUCCESS, params );
},...

答案 8 :(得分:0)

编辑:我偶然发现了一个非常类似的问题,我的解决方案是使用vuex getter: https://vuex.vuejs.org/en/getters.html
您的类别实际上是您产品的“计算”版本。将类别作为获取者可以使它们与产品保持同步,并避免重复存储中的数据。

为了回答标题中的问题,我留下原来的答案 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)
 }
}

如您所见,您可以直接调用突变本身。 (正如丹尼尔所说,毕竟它们只是简单的功能)
我相信这是对原始问题更合适的答案:它是一种在没有代码重复或额外功能的情况下编写突变的实际方法

答案 9 :(得分: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
}

这应该解决它。您可以从操作中将提交注入到您的突变中,以便可以从您的突变中进行提交。希望这会有所帮助

答案 10 :(得分:0)

我更喜欢打mutations.SET_CATEGORIES(state)而不是: -通过人工的操作调用2次不同的提交 -或在突变内进行commit(),因为这会使单元测试更加困难。

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

我认为您不需要在VueToolbox中看到SET_CATEGORIES。无论如何,时间旅行应该工作。请纠正我的错误。

答案 11 :(得分:0)

我认为

从另一个变异中调用变异是一个坏主意,因为难以调试状态和组件

const mutations = {
    mutationOne(state, payload){
        this.commit("mutationTwo", payload)
    },
    mutationTwo(state, payload){
        console.log("called from another mutation", payload)
    }
}

但是您可以编写简单的函数并且函数可以重用

function mysecondfn(state,payload){
{
// do your stuff here
}


const mutations = {
    mutationOne(state, payload){
mysecondfn(state,payload)
     },

}

答案 12 :(得分:0)

另一种适合我的解决方案:

this._mutations.mutationFunction[0]()