Vuex es una librería que ofrece Vue para gestionar el estado de la aplicación, centralizar información y funciones, haciéndolas accesibles desde cualquier componente. Se organiza de la siguiente manera:
state: es el estado, un objeto que puede contener cualquier tipo de información; la información que almacenamos de forma centralizada en toda la aplicación.mutations: las mutaciones son las únicas funciones que pueden modificar el estado. Son llamadas por las acciones, e inicializadas en el componente a utilizar a través de un commit o inicializarse a través de una acción. Son síncronas.actions: las acciones son funciones que contienen la lógica de negocio. Pueden cambiar el estado llamando a mutaciones a través de commit. Pueden llamar a otras acciones a través de dispatch. La forma de inicializarse en el componente es a través de dispatch.getters: son funciones que no cambian el estado, pero sí lo formatean para que podamos utilizar la información cómo necesitemos.
No todas las aplicaciones necesitarán Vuex, tendrá sentido si se reutiliza el código o si hay componentes distantes que necesiten comunicarse. No tiene sentido, por ejemplo, que hagas un getter si solo lo vas a utilizar una vez y no se comunica con otro componente, para eso mejor una propiedad computed en el mismo componente que lo necesita.
Aquí podemos ver el ciclo de cómo se ejecuta:
Cómo definir nuestro vuex store
En nuestro proyecto, definiremos Vuex ensrc/store/index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import moduloTexto from './modules/moduloTexto'
import moduloCuenta from './modules/moduloCuenta'
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
// Dividimos el estado en diferentes módulos que hagan referencia a diferentes ámbitos
// Podríamos tener un módulo dedicado, por ejemplo, al login
moduloTexto, moduloCuenta
},
// Para hacer que el estado persista tras refrescar la página
plugins: [createPersistedState()]
})
En este ejemplo, sólo se están importando dos módulos. Podemos añadir la funcionalidad directamente en este archivo, pero si tenemos estados de diferentes ámbitos, es mejor tener varios módulos para favorecer la legibilidad del código. Los módulos se definirán en archivos.jsque se encontrarán ensrc/store/modules/. Por ejemplo,moduloCuenta.js:
export default {
// namespaced para mapear especificando el módulo ...mapState('nombreModulo', ['estado', 'otroestado'])
// también para los dispatch -> dispatch("modulo/nombreAction")
namespaced: true,
// ESTADO
state: {
cuenta: 0,
},
// MUTACIONES: sólo estas pueden modificar el estado
mutations: {
SUMAR(state, valor) {
state.cuenta += valor;
},
RESETEAR(state) {
state.cuenta = 0;
},
},
// ACCIONES: se encargan de la lógica de negocio y llaman a las mutaciones
actions: {
sumarX({ commit }, valor) {
commit("SUMAR", valor);
},
resetear({ commit }) {
commit("RESETEAR");
},
},
// GETTERS: para propiedades calculadas
getters: {
isMillonario: (state) => state.cuenta > 999999,
},
};
Cuando tenemos diferentes módulos en nuestro store, estableceremos namepsace=true para que al utilizar su funcionalidad desde los componentes haya que indicar a qué módulo corresponden, haciendo también que el código sea más fácil de comprender.
Acceder desde componentes
Desde los componentes podemos acceder a la funcionalidad del store de las siguientes formas.
State y Getters
Para el estado y los getters disponemos respectivamente demapStateymapGetters:
import { mapGetters } from "vuex";
import { mapState } from "vuex";
export default {
computed: {
...mapState("modulo", ["variableState", "otroState"]),
...mapGetters("modulo", ["isTal", "isCual"])
}
}
De esta forma tendríamos disponibles estas opciones para llamarlas de la misma forma que al resto de variables o computed variables del componente, con this. en el código JavaScript, y con el nombre directamente en el template.
Si las variables del estado o getters que mapeamos no están en un módulo, sino directamente en elindex.jsde nuestro store, se indicaría directamente el array con sus nombres:
import { mapGetters } from "vuex";
import { mapState } from "vuex";
export default {
computed: {
...mapState(["variableState", "otroState"]),
...mapGetters(["isTal", "isCual"])
}
}
Actions
Para ejecutar acciones desde nuestros componentes, no tendremos que importar nada, simplemente usardispatchde esta manera:
this.$store.dispatch("modulo/action", parametro);
Si la acción no corresponde a ningún módulo, sólo tenemos que llamarla con el nombre de la propia acción. Las acciones son funciones que pueden tener parámetros, y como vemos éstos se le pasan después del nombre de la acción, separados por comas.
