web-dev-qa-db-ja.com

Vuexストアの突然変異の1つからコミットを呼び出すことはできますか

次のような 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.committhis.commitを試しましたが、これらも同様のエラーを出しました。

47
Saurabh

すでに突然変異を行っている場合、別の突然変異をcommitする方法はありません。突然変異は、状態を変更する同期呼び出しです。ある突然変異内では、別の突然変異をコミットすることはできません。

VuexのAPIリファレンスは次のとおりです。 https://vuex.vuejs.org/en/api.html

ご覧のとおり、ミューテーションハンドラはstatepayloadのみを受け取り、それ以上は受け取りません。したがって、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つの突然変異をコミットすることです。

32
Mani

絶対に2つの突然変異をコミットする必要がある場合、アクションからそれをしてみませんか?アクションは非同期操作を実行する必要はありません。次のような状態の場合と同じ方法で、アクションのcommitメソッドを非構造化できます。

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

ミューテーション間でコードを共有するには、作業を実行する新しい関数を作成し、それを再利用できます。幸いなことに、突然変異は単なる古い関数であり、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)
}
22

記録のために。突然変異メソッドから他の突然変異を呼び出すには、次のようにします。

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

そして、複数の突然変異の間の状態に影響する一般的なコードがある場合、すべての突然変異で同じコードを複製する必要がありますか?または、それを行うためのより良い方法がありますか?

9
Nacho

アクションに関するVuexドキュメント を読むと、それらが何のために作られているかが非常に明確です。

  • 状態を変更するのではなく、突然変異をコミットする
  • 任意の非同期操作を含めることができます

アクションcan(notmust)には非同期コードが含まれます。実際、次の例は正しいです

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

複数のミューテーションを実行するためのアクションの使用に問題はありません。

5
Wanny Miarelli

あなたの場合、あなたはただ一つの突然変異、すなわち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を介してのみ変更できます。

2
jiv-e

編集:私は非常に似た問題に出くわし、私のための解決策は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)
 }
}

ご覧のとおり、突然変異そのものを直接呼び出すことができます。 (ダニエルが言ったように、彼らは結局のところ単なる関数です)
これは元の質問に対するより適切な答えだと思います。これは、コードの重複や余分な機能なしに突然変異を構成する実際の方法です

0
Guillaume Meral
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
}

これで修正されるはずです。アクションからミューテーションにコミットを注入して、ミューテーションからコミットできます。お役に立てれば

0
Andrei