Чи можу я зателефонувати коміту з однієї з мутацій у магазині Vuex


78

У мене є магазин 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
}

Я хочу викликати mutation: SET_CATEGORIESfrom mutation:, SET_PRODUCTSАле це видає мені помилку:

projectFilter.js: 22 Не спійманий (обіцяно) ReferenceError: коміт не визначений (…)

Яким повинен бути правильний спосіб це зробити. Я спробував store.commitі this.commit, але це також дало подібні помилки.


1
Пов’язане (закрите) видання: github.com/vuejs/vuex/issues/907
Амір Алі Акбарі

Привіт @Saurabh, я протестував відповідь Kubiwama Adrien, і, здається, у ній є те, що потрібно, можливо, протестувати та оновити цей форум останньою відповіддю? Дякую!
Ірфанді Джип

Чому б не використовувати дію і не викликати всередині неї кілька мутацій?
Серпень

Відповіді:


47

Коли ви вже робите мутацію, немає можливості перейти до 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: Будь ласка, зверніться до відповіді нижче, наданої Даніелем С. Дебоером . Правильним методом є здійснення двох мутацій за одну дію, як описано у його відповіді.


6
Цікаво, чому заборонено здійснювати мутацію з іншої мутації? Деякі мутації можуть бути настільки атомними, що їх повинні використовувати більші мутаційні функції. У поточній версії, через це обмеження, має бути дублювання коду.
Аскан,

Так, можна отримати коміт від іншої мутації без побічних ефектів. Але налагодження неправильної зміни стану, коли мутації викликають одне одного, призведе до дуже поганого досвіду розробника. Думаю, саме тому його не рекомендують і не дозволяють. Але на щастя, у нас є це просте рішення - ми завжди можемо визначити одну мутацію, яка вносить кілька змін стану, як видно з цього питання / відповіді.
Мані

ІМХО, відповідь нижче (вчиніть дві речі з однієї дії). Він чистіший і читабельніший.
JCKödel

@ JCKödel Я погоджуюсь, правильною відповіддю має бути наведена нижче (вчинити дві мутації від дії), надана Даніелем. Я вкладу примітку у свою відповідь вище, щоб посилатися на кращу відповідь нижче.
Мані

@Mani, чому це не є кращим, ніж відповідь Дані? Я вважав, що це було семантично більш правильним з точки зору Vuex, оскільки дія призначена в основному для асинхронних операцій.
Alex Napitupulu,

110

Якщо ви абсолютно мусите здійснити дві мутації, чому б не зробити це з дії? Дії не повинні виконувати асинхронні операції. Ви можете деструктурувати метод коміту у своїй дії так само, як це робите із станом так:

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

4
Так, це має бути відповіддю.
Тьяго Йоїті,

3
Чому б і ні? .. За допомогою vue-native-websocke вам потрібно обробляти дані із сервера ws в мутації (SOCKET_ONMESSAGE) ... І їх немає можливості викликати дію з мутації.
Constantin De La Roche

58

Для запису. Щоб викликати інші мутації за допомогою методу мутації, зробіть це так:

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

6
Це нова (іш) функція Vuex? Здивований, що пішло два з половиною роки, щоб хтось вказав на чітко правильну відповідь.
Майкл Хейс,

3
Я не зовсім впевнений, чи вважається це найкращою практикою. Однак ця відповідь безпосередньо відповіла на питання. без надання альтернатив, запропонованих іншими за допомогою action. Я протестував, і, здається, він працює добре. Я думаю, що ця відповідь повинна бути зверху. Це рішення вже обговорювалось у Vuex Github - Будь ласка, додайте можливість викликати мутацію з іншої мутації №907, якщо хтось бажає прочитати більше доказів.
Irfandy Jip

15
До речі, якщо у вашому modulesпросторі імен, навіть якщо він знаходиться під тим самим файлом, ви повинні отримати до нього доступ на this.commit('modulesName/mutationName')всякий випадок, якщо хтось цікавився. Якщо вам потрібна додаткова інформація, це завжди гарне нагадування про те, щоб просто зробити console.log(this)всередині мутації, здається, вона містить той самий екземпляр Vue, до якого ви також можете отримати доступ $routeзвідти.
Irfandy Jip

30

Щоб розподілити код між мутаціями, потрібно створити нову функцію, яка виконує роботу, яку потім можна використовувати повторно. На щастя, мутації - це звичайні старі функції, і ми можемо передати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)
}

Я думаю, що це дає помилку щодо ланцюгового стану поза мутацією
Дрю Бейкер

Що змушує вас думати про це? Поки ви телефонуєте лише setCategoriesзсередини мутації, це буде добре.
Даніель Бакмастер

Це спрацювало для мене, але я залишив реалізацію функції як мутацію і просто назвав mutations.setCategories (state) із функції.
jason

12

І якщо у мене є якийсь загальний код, який впливає на стан між кількома мутаціями, я повинен дублювати той самий код на всіх своїх мутаціях? Або є кращий спосіб це зробити?


9
Тиша оглушає. Я теж хотів би отримати відповідь на це.
daninthemix

1
@Nacho див. Відповідь, яку я щойно створив. Це не ідеально, але це найкраще, що я знаю
Даніель Бакмастер

Я згоден з Даніелем. Функції - це спосіб повторного використання коду.
cstricklan

1
Так - мутація - це просто функція, яка приймає стан як аргумент і модифікує його. Ви можете оголосити скільки завгодно допоміжних функцій і використовувати їх повторно.
Кріс Вільямсон

1
Будь ласка, опублікуйте відповідь лише тоді, коли у вас є відповідь. Якщо ви хочете щось запитати, створіть нову тему.
Пабло

5

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

  • здійснювати мутації замість мутації стану
  • може містити довільні асинхронні операції

Дії можуть (не повинні ) містити асинхронний код. Насправді наступний приклад правильний

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

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


3

У вашому випадку ви повинні розглянути можливість мати лише одну мутацію, а саме 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.


1

Редагувати: Я натрапив на дуже подібну проблему, і рішенням для мене було використання гейтера vuex: 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)
 }
}

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


Виклик функції мутації - це не те саме , що здійснення мутації.
Еміль Бержерон,

Не могли б ви детальніше сказати? Це насправді проблема, оскільки ми називаємо це з іншої мутації?
Гійом Мерал,

Наприклад, обробник для зареєстрованих плагінів не буде викликаний для другої мутації. Це означає, що інструменти розробника Vue не відображатимуть другу мутацію у списку мутацій, до якої ви можете "подорожувати у часі".
Еміль Бержерон,

Але варіант використання - це одна мутація, яка робить дві речі. Я розумію вашу думку, але в такому випадку ви не хочете мати стан магазину, який має десинхронізовані списки товарів і категорій.
Гійом Мерал,

1
Так, саме це я мав на увазі під "альтернативою рішенням Даніеля Бакмастера". Це моя перша відповідь StackOverflow, можливо, мені слід було б прокоментувати його рішення.
Гійом Мераль

1

Спочатку призначте кнопку Vue змінній: У main.js:

  export const app = new Vue({  
  router,
  vuetify,
  store,....

Потім імпортуйте змінну "app" у файл js, де ви визначите мутацію: У modules.js:

import { app } from "../../main";

Тепер ви можете використовувати його як "додаток. $ Store.commit":

mutations: {
[AUTH_SET_TOKEN]: () => {
app.$store.commit(USER_SUCCESS, params );
},...

0

Я вважаю за краще зателефонувати, mutations.SET_CATEGORIES(state)а не: - викликати 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)
 }
}

На мою думку, вам не потрібно бачити SET_CATEGORIESу VueToolbox. Подорож у часі повинна працювати в будь-якому випадку. Будь ласка, виправте мене, якщо я помиляюся.


0

Я думаю

називати мутацію з іншої мутації поганою ідеєю через важкий для налагодження стан та компоненти

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

}

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

Це повинно це виправити. Ви можете ввести коміт у свою мутацію з дії, щоб ви могли зробити коміт із своєї мутації. Сподіваюся, це допомагає


Будь ласка, додайте пояснення до свого коду: що саме потрібно змінити і чому? Майте на увазі, що ОП повинен мати можливість вчитися на основі вашої відповіді
Ніко Хаасе,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.