我能从 Vuex 商店的一个突变中调用 commit 吗

我有一个 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,但是这给了我一个错误:

Js: 22未捕获(在承诺中) ReferenceError: commit 不定义(...)

什么应该是正确的方法来做到这一点。我尝试了 store.committhis.commit,但这些也给类似的错误。

117484 次浏览

当你已经在做一个突变时,就没有办法再做一个 commit突变。变异是改变状态的同步调用。在一次变异中,你将无法进行另一次变异。

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

如您所见,变异处理程序只接收 statepayload,仅此而已。因此你得到的是 commit作为 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 回答.

And if I have some common code that affects state between multiple mutations, I have to duplicate the same code on all my mutations? Or there's a better way to do that?

要在突变之间共享代码,必须创建一个执行该工作的新函数,然后可以重用该函数。幸运的是,变换只是普通的老函数,我们可以随心所欲地传递 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)
}

在您的情况下,您应该考虑只有一个变异,即 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 进行更改。

如果你绝对必须提交两个突变,为什么不从一个动作?操作不必执行异步操作。您可以像处理 state 一样解构操作中的 commit 方法,如下所示:

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

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

为了回答题目中的问题,我保留原来的答案。
丹尼尔 · 巴克马斯特解决方案的另一种选择:

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

如你所见,你可以直接调用突变本身。(正如丹尼尔所说,它们毕竟只是简单的函数)
我相信这是对最初问题的一个更合适的回答: 它是一种实际的组合突变的方法,不需要代码复制或者额外的函数

阅读 关于行动的 Vuex 文档,你就会清楚地知道它们是为什么而生的。

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

Actions 可以 (not 必须的) contain asynchronous code. In fact, the following example is correct

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

我认为使用操作来执行多个突变没有任何问题。

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
}

这个应该能修好。你可以将提交从动作注入到你的突变中,这样你就可以从你的突变中提交。希望这个能帮上忙

为了记录在案,从一个突变方法调用其他突变是这样做的:

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

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

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

然后将“ app”变量导入到 js 文件中,在该文件中定义变异: 在 module. js 中:

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

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

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

我更喜欢打电话给 mutations.SET_CATEGORIES(state)而不是: - 从人工 action调用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)
}
}

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.

i think

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

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

but you can write simple function and function can reusable

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




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


}

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

this._mutations.mutationFunction[0]()

you can access to all vuex

this.app.store.commit("toast/show", {
mssg:this.app.i18n.t('order.ordersummary.notifymessage'),
type: "danger",
});

access to $i18n in vuex

this.app.i18n.t('order.ordersummary.notifymessage')

用这个

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