Puedo llamar a commit desde una de las mutaciones en Vuex store


Tengo una tienda vuex , como la siguiente:

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
}

Quiero llamar mutación: SET_CATEGORIES de mutación: SET_PRODUCTS, pero esto me da error:

Filtro de proyecto.js: 22 Uncaught (in promise) ReferenceError: commit no está definido ({)

¿Cuál debería ser la manera correcta de hacer esto. Traté store.commit y this.commit, pero estos también dieron errores similares.

Author: Saurabh, 2016-11-08

7 answers

Cuando usted ya está haciendo una mutación, no hay manera de commit otra mutación. Una mutación es una llamada sincrónica que cambia el estado. Dentro de una mutación, usted no será capaz de cometer otra mutación.

Aquí está la referencia de API para Vuex: https://vuex.vuejs.org/en/api.html

Como puede ver, un manipulador de mutaciones solo recibe state y payload, nada más. Por lo tanto usted está consiguiendo commit como undefined.

En su caso anterior, puede configurar el PRODUCTO y CATEGORÍAS como parte del mismo controlador de mutaciones como un solo commit. Puede probar si el siguiente código funciona:

// mutations
const mutations = {
    SET_PRODUCTS_AND_CATEGORIES: (state, response) => {
        state.products = response.data.products
        state.categories = state.products.map(function(product) { return product.category})
    },
    // ...
}

EDITAR: Por favor refiérase a la respuesta a continuación, proporcionada por Daniel S. Deboer. El método correcto es cometer dos mutaciones de una sola acción, como se describe en su respuesta.

 17
Author: Mani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-22 15:57:13

Si es absolutamente necesario cometer dos mutaciones, ¿por qué no hacerlo desde una acción? Las acciones no tienen que realizar operaciones asincrónicas. Puedes desestructurar el método commit en tu acción de la misma manera que lo haces con state así:

commitTwoThings: ({commit}, payload) => {
  commit('MUTATION_1', payload.thing)
  commit('MUTATION_2', payload.otherThing)
}
 45
Author: Daniel S. Deboer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-31 19:05:28

Para compartir código entre mutaciones, debe crear una nueva función que realice el trabajo, que luego puede reutilizar. Afortunadamente, las mutaciones son simplemente funciones antiguas, y podemos pasar el parámetro state como queramos, por lo que esto es bastante fácil de hacer.

Por ejemplo:

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)
}
 15
Author: Daniel Buckmaster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-25 06:23:26

Y si tengo algún código común que afecta el estado entre múltiples mutaciones, ¿tengo que duplicar el mismo código en todas mis mutaciones? ¿O hay una mejor manera de hacerlo?

 8
Author: Nacho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-05 20:39:41

Leyendo la documentación de Vuex sobre Acciones, está bastante claro para qué están hechas.

  • cometer mutaciones en lugar de mutar el estado
  • puede contener operaciones asíncronas arbitrarias

Las acciones pueden (no deben ) contener código asíncrono. De hecho, el siguiente ejemplo es correcto

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

No veo ningún problema en el uso de acciones para realizar mutaciones múltiples.

 3
Author: Wanny Miarelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-25 20:55:41

En su caso, debe considerar tener solo una mutación, a saber, SET_PRODUCTS.

// mutations
const mutations = {
 SET_PRODUCTS: (state, response) => {
   state.products = response.data.products
   state.categories = state.products.map(function(product) { return product.category})
 }
}

Nunca debería tener necesidad de llamar a SET_CATEGORIES por separado. ¡Piénsalo! Las categorías solo pueden mutar si se cambian los productos. Y los productos solo pueden cambiar a través de SET_PRODUCTS.

 2
Author: jiv-e,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-16 16:30:59

Editar: Me topé con un problema muy similar y la solución para mí fue utilizar un vuex getter : https://vuex.vuejs.org/en/getters.html
Sus categorías son en realidad una versión "computada" de sus productos. Tener categorías como un getter le permite mantenerlos sincronizados con los productos y evita duplicar los datos en su tienda.

Para responder a la pregunta en el título dejo mi respuesta original.
Una alternativa a la solución de 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)
 }
}

Como puedes ver, podrías llamar directamente a la mutación en sí. (como dijo Daniel, después de todo son funciones simples)
Creo que esta es una respuesta más apropiada a la pregunta original : es una forma real de componer mutaciones sin duplicación de código o funciones adicionales

 0
Author: Guillaume Meral,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-29 17:19:34