我有一个 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_PRODUCTS
中调用突变:SET_CATEGORIES
,但这给了我错误:
projectFilter.js:22 Uncaught (in promise) ReferenceError: commit is not defined(…)
什么应该是正确的方法来做到这一点。我尝试了 store.commit
和 this.commit
,但它们也给出了类似的错误。
如果你绝对必须提交两个突变,为什么不从一个动作中做呢?操作不必执行异步操作。您可以像使用 state 一样解构 action 中的 commit 方法,如下所示:
commitTwoThings: ({commit}, payload) => {
commit('MUTATION_1', payload.thing)
commit('MUTATION_2', payload.otherThing)
}
作为记录。要从突变方法中调用其他突变,请执行以下操作:
const mutations = {
mutationOne(state, payload){
this.commit("mutationTwo", payload)
},
mutationTwo(state, payload){
console.log("called from another mutation", payload)
}
}
action
提出的替代方案。我已经对其进行了测试,它似乎运行良好。我认为这个答案应该放在首位。如果有人有兴趣阅读更多证明,此解决方案已在 Vuex Github - Please add an ability to call mutation from another mutation #907 中讨论过。
modules
是命名空间的,即使它在同一个文件下,您也必须通过 this.commit('modulesName/mutationName')
访问它,以防万一有人想知道。如果您需要更多信息,最好提醒您只需在突变中执行 console.log(this)
,它似乎与 Vue
拥有相同的实例,您也可以从那里访问 $route
。
如果您已经在进行突变,则无法commit
进行另一个突变。突变是改变状态的同步调用。在一个突变中,您将无法提交另一个突变。
以下是 Vuex 的 API 参考:https://vuex.vuejs.org/en/api.html
如您所见,突变处理程序仅接收 state
和 payload
,仅此而已。因此,您将 commit
作为 undefined
。
在上述情况下,您可以将 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 提供的以下答案。正确的方法是从一个动作中提交两个突变,如他的回答中所述。
要在突变之间共享代码,您必须创建一个执行该工作的新函数,然后您可以重用该函数。幸运的是,突变只是普通的旧函数,我们可以随意传递 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)
}
setCategories
,就可以了。
如果我有一些影响多个突变之间状态的通用代码,我必须在所有突变上复制相同的代码?或者有更好的方法来做到这一点?
阅读 Vuex documentation on Actions,很清楚它们的用途。
提交突变而不是改变状态
可以包含任意异步操作
动作可以(不是必须)包含异步代码。其实下面的例子是正确的
increment (context) {
context.commit('increment')
}
我认为使用操作执行多个突变没有任何问题。
在您的情况下,您应该考虑只有一个突变,即 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 进行更改。
编辑:我偶然发现了一个非常相似的问题,我的解决方案是使用 vuex getter:https://vuex.vuejs.org/en/getters.html
您的类别实际上是您产品的“计算”版本。将类别作为 getter 可让您使它们与产品保持同步,并避免复制商店中的数据。
为了回答标题中的问题,我留下了我原来的答案。 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)
}
}
如您所见,您可以直接调用突变本身。 (正如丹尼尔所说,它们毕竟只是普通函数)我相信这是对原始问题的更合适的答案:它是一种无需代码重复或额外功能即可组合突变的实际方法
我更喜欢调用 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)
}
}
我的观点是你不需要在 VueToolbox 中看到 SET_CATEGORIES
。无论如何,时间旅行应该有效。如果我错了,请纠正我。
首先,将 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 );
},...
我认为
从另一个突变调用突变是个坏主意,因为难以调试状态和组件
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)
},
}
另一个适合我的解决方案:
this._mutations.mutationFunction[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
}
这应该解决它。您可以从操作中将提交注入到您的突变中,以便您可以从您的突变中提交。希望这可以帮助
你可以访问所有的 vuex
this.app.store.commit("toast/show", {
mssg:this.app.i18n.t('order.ordersummary.notifymessage'),
type: "danger",
});
在 vuex 中访问 $i18n
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)
}
}
不定期副业成功案例分享