Могу ли я вызвать фиксацию из одной из мутаций в хранилище Vuex

У меня есть магазин 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 Не показано (в обещании) ReferenceError: commit не определен (...)

Каким должен быть правильный способ сделать это. Я попробовал store.commit и this.commit, но они также дали похожие ошибки.

Ответы

Ответ 1

Когда вы уже делаете мутацию, нет возможности commit другую мутацию. Мутация - это синхронный вызов, который изменяет состояние. В течение одной мутации вы не сможете совершить другую мутацию.

Вот ссылка API для Vuex: https://vuex.vuejs.org/en/api.html

Как вы можете видеть, обработчик мутации получает только state и payload, не более того. Поэтому вы получаете commit как undefined.

В вашем случае выше вы можете установить ПРОДУКТ и КАТЕГОРИИ как часть одного и того же обработчика мутаций в качестве одного фиксации. Вы можете попробовать, если работает следующий код:

// 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: Пожалуйста, обратитесь к приведенному ниже ответу, предоставленному Даниэлем С. Дебоэром. Правильный метод состоит в том, чтобы зафиксировать две мутации из одного действия, как описано в его ответе.

Ответ 2

Если вы абсолютно должны совершить две мутации, почему бы не сделать это из-за действия? Действиям не нужно выполнять асинхронные операции. Вы можете разрушить метод фиксации в своем действии так же, как и в таком состоянии:

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

Ответ 3

Чтобы совместно использовать код между мутациями, вы должны создать новую функцию, которая выполняет работу, которую вы затем можете повторно использовать. К счастью, мутации - это просто старые старые функции, и мы можем передавать параметр 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)
}

Ответ 4

Для записи. Чтобы вызвать другие мутации из метода мутации, сделайте это так:

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

Ответ 5

И если у меня есть общий код, который влияет на состояние между несколькими мутациями, я должен дублировать один и тот же код на всех моих мутациях? Или есть лучший способ сделать это?

Ответ 6

Прочитав документацию Vuex по действиям, вы поймете, для чего они созданы.

  • совершать мутации вместо того, чтобы мутировать состояние
  • может содержать произвольные асинхронные операции

Действия могут (не должны) содержать асинхронный код. На самом деле следующий пример верен

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

Я не вижу проблем в использовании действий для выполнения нескольких мутаций.

Ответ 7

В вашем случае вы должны учитывать наличие только одной мутации, а именно 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.

Ответ 8

Редактирование: я наткнулся на очень похожую проблему, и решение для меня состояло в использовании vuex getter: https://vuex.vuejs.org/en/getters.html
Ваши категории на самом деле являются "вычисленными" версиями ваших продуктов. Наличие категорий в качестве геттера позволяет вам синхронизировать их с продуктами и избегать дублирования данных в вашем магазине.

Чтобы ответить на вопрос в названии, я оставляю свой первоначальный ответ.
Альтернатива решению Даниэля Бакмастера:

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

Как вы можете видеть, вы можете напрямую вызвать мутацию. (как сказал Даниэль, они просто простые функции)
Я считаю, что это более подходящий ответ на исходный вопрос: это реальный способ составления мутаций без дублирования кода или дополнительных функций

Ответ 9

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
}

Это должно это исправить. Вы можете добавить коммит в вашу мутацию из действия, чтобы вы могли коммитить из вашей мутации. Надеюсь это поможет