Могу ли я вызвать фиксацию из одной из мутаций в хранилище 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
}
Это должно это исправить. Вы можете добавить коммит в вашу мутацию из действия, чтобы вы могли коммитить из вашей мутации. Надеюсь это поможет