我可以从 Vuex 商店中的一个突变调用提交吗
Can I call commit from one of mutations in Vuex store
我有一家 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 (in promise) ReferenceError: commit is not defined(…)
执行此操作的正确方法应该是什么。我尝试了 store.commit
和 this.commit
,但这些也给出了类似的错误。
当你已经在做一个突变时,就没有办法 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)
}
在你的情况下,你应该考虑只有一个突变,即 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.
改变
如果您绝对必须进行两次突变,为什么不从一个动作中进行呢?操作不必执行异步操作。您可以像处理状态一样在操作中解构提交方法:
commitTwoThings: ({commit}, payload) => {
commit('MUTATION_1', payload.thing)
commit('MUTATION_2', payload.otherThing)
}
编辑:我偶然发现了一个非常相似的问题,我的解决方案是使用 vuex getter:
https://vuex.vuejs.org/en/getters.html
您的类别实际上是产品的 "computed" 版本。将类别设置为 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)
}
}
如您所见,您可以直接调用突变本身。 (正如大牛所说,毕竟它们只是普通的函数)
我相信这是对原始问题的更合适的答案:它是一种在没有代码重复或额外功能的情况下组合突变的实际方法
阅读 Vuex documentation on Actions,很清楚它们的用途。
- 提交突变而不是改变状态
- 可以包含任意异步操作
操作可以(并非必须)包含异步代码。其实下面这个例子是正确的
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文件中:
在 modules.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)
}
}
我的意见是你不需要在 VueToolbox 中看到 SET_CATEGORIES
。时间旅行无论如何都应该有效。如有错误请指正
我觉得
从另一个突变调用突变是个坏主意,因为很难调试状态和组件
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]()
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)
}
}
我有一家 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 (in promise) ReferenceError: commit is not defined(…)
执行此操作的正确方法应该是什么。我尝试了 store.commit
和 this.commit
,但这些也给出了类似的错误。
当你已经在做一个突变时,就没有办法 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)
}
在你的情况下,你应该考虑只有一个突变,即 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.
改变如果您绝对必须进行两次突变,为什么不从一个动作中进行呢?操作不必执行异步操作。您可以像处理状态一样在操作中解构提交方法:
commitTwoThings: ({commit}, payload) => {
commit('MUTATION_1', payload.thing)
commit('MUTATION_2', payload.otherThing)
}
编辑:我偶然发现了一个非常相似的问题,我的解决方案是使用 vuex getter:
https://vuex.vuejs.org/en/getters.html
您的类别实际上是产品的 "computed" 版本。将类别设置为 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)
}
}
如您所见,您可以直接调用突变本身。 (正如大牛所说,毕竟它们只是普通的函数)
我相信这是对原始问题的更合适的答案:它是一种在没有代码重复或额外功能的情况下组合突变的实际方法
阅读 Vuex documentation on Actions,很清楚它们的用途。
- 提交突变而不是改变状态
- 可以包含任意异步操作
操作可以(并非必须)包含异步代码。其实下面这个例子是正确的
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文件中: 在 modules.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)
}
}
我的意见是你不需要在 VueToolbox 中看到 SET_CATEGORIES
。时间旅行无论如何都应该有效。如有错误请指正
我觉得
从另一个突变调用突变是个坏主意,因为很难调试状态和组件
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]()
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)
}
}