次のような 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})
},
// ...
}
EDIT:Daniel S. Deboerが提供する以下の回答を参照してください。正しい方法は、彼の答えで説明されているように、単一のアクションから2つの突然変異をコミットすることです。
絶対に2つの突然変異をコミットする必要がある場合、アクションからそれをしてみませんか?アクションは非同期操作を実行する必要はありません。次のような状態の場合と同じ方法で、アクションのcommitメソッドを非構造化できます。
commitTwoThings: ({commit}, payload) => {
commit('MUTATION_1', payload.thing)
commit('MUTATION_2', payload.otherThing)
}
ミューテーション間でコードを共有するには、作業を実行する新しい関数を作成し、それを再利用できます。幸いなことに、突然変異は単なる古い関数であり、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)
}
記録のために。突然変異メソッドから他の突然変異を呼び出すには、次のようにします。
const mutations = {
mutationOne(state, payload){
this.commit("mutationTwo", payload)
},
mutationTwo(state, payload){
console.log("called form another mutation", payload)
}
}
そして、複数の突然変異の間の状態に影響する一般的なコードがある場合、すべての突然変異で同じコードを複製する必要がありますか?または、それを行うためのより良い方法がありますか?
アクションに関するVuexドキュメント を読むと、それらが何のために作られているかが非常に明確です。
アクションcan(notmust)には非同期コードが含まれます。実際、次の例は正しいです
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ゲッターを使用することでした: 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)
}
}
ご覧のとおり、突然変異そのものを直接呼び出すことができます。 (ダニエルが言ったように、彼らは結局のところ単なる関数です)
これは元の質問に対するより適切な答えだと思います。これは、コードの重複や余分な機能なしに突然変異を構成する実際の方法です
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
}
これで修正されるはずです。アクションからミューテーションにコミットを注入して、ミューテーションからコミットできます。お役に立てれば