Versiones comparadas

Clave

  • Se ha añadido esta línea.
  • Se ha eliminado esta línea.
  • El formato se ha cambiado.

Tabla de contenidos

...

¿Puedo usar Vuex?

SÍ, PERO...

Como vamos a ver a continuación, Vuex sirve para guardar el estado global de la aplicación. Este estado por defecto es volátil, cuando salgamos de la aplicación (ya sea cerrando la ventana, navegando a otro sitio, etc) este estado se borrará. 

Veremos que tenemos una opción para hacer este estado persistente, para poder mantenerlo aunque salgamos de la aplicación, pero esto guarda los datos en el local storage del navegador, los hace accesibles, por lo tanto, podemos usar Vuex, pero bajo ningún concepto podemos perisitir datos de usuario u otros datos sensibles.

Si necesitamos guardar estos datos, debemos hacerlos a través del backend, gestionando sesiones como se explica en esta guía: Gestión de sesiones web.

¿Qué es Vuex?

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 Se ejecutan 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.

...

Aquí podemos ver el ciclo de cómo se ejecuta:

Cómo definir nuestro Vuex store

En nuestro proyecto, definiremos Vuex en src/store/index.js:

Bloque de código
languagejs
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()]
})

Definir un módulo para un servicio

Para definir nuestros módulos, lo haremos bajo la carpeta store/ de nuestro servicio. Por ejemploEn 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 .js que se encontrarán en src/store/modules/. Por ejemplo, moduloCuenta.js:

Bloque de código
languagejs
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) {
	  // Lógica
	  // ..
      commit("SUMAR", valor);
    },
    resetear({ commit }) {
	  // Lógica
	  // .. 
      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.

...

Los módulos tienen que seguir esta notación, la que hemos indicado previamente, para ser leídos correctamente por Vuex.

Añadir módulo al store global de POSE

Para añadir el módulo que hemos creado, lo haremos en el archivo app.store.modules.js, situado en /src. tendremos que importarlo, y añadirlo al final de la lista dentro del export default:

Bloque de código
languagejs
import auth from './auth/store/modules/auth';
import pages from './shared/store/modules/pages';
import language from './shared/store/modules/language';
import notifications from './shared/store/modules/notifications';
import user from './user/store/modules/user';
import services from './campus-virtual/portal-servicios/store/modules/services';
import syllabus from './campus-virtual/historico-guias/store/modules/syllabus';

export default {
  auth,
  pages,
  language,
  notifications,
  user,
  services,
  syllabus,
};

Cómo acceder desde componentes (Options API)

Desde los componentes podemos acceder a la funcionalidad del store de las siguientes formas.

...

Estado y Getters

Para consultar el estado y los getters disponemos respectivamente de mapState mapGetters.  Estos nos permiten mapearlos a propiedades computed:

...

Si las variables del estado o getters que mapeamos no están en un módulo, sino directamente en elel index.jsde nuestro store, se indicaría directamente el array con sus nombres:

...

Bloque de código
languagejs
this.$store.state.modulo.variable
this.$store.getters["modulo/getter"]

Actions

Mutaciones (commit)

Las mutaciones se hacen utilizando commit. Esto lo utilizaremos para modificar variables del estado directamente. Esto es, si sólo queremos modificar el valor de variables del estado, utilizaremos commit, si necesitamos más lógica, utilizaremos acciones (lo vemos en el siguiente apartado). 

IMPORTANTE: el commit se ejecuta de forma SÍNCRONA.

Ejemplo:

Bloque de código
languagejs
// Desde un componente
this.$store.commit("NOMBRE_MUTACION", valor)

// Desde un archivo js, habiendo importado store
store.commit("NOMBRE_MUTACION", valor)

Acciones (dispatch)

Para ejecutar acciones utilizamos dispatch. Estas pueden realizar mutaciones llamando a commit, y las utilizaremos cuando se requieran cálculos o lógica adicionalesPara ejecutar acciones desde nuestros componentes, no tendremos que importar nada, simplemente usar dispatch de esta manera:

Bloque de código
languagejs
this.$store.dispatch("modulo/action", datos);

...

Las acciones sólo toman un parámetro para los datos, por lo que si queremos pasarle varios campos, deberemos utilizar un objeto que los contenga, tanto para pasarlos en el dispatch como en la definición de la acción.

IMPORTANTE: el dispatch se ejecuta de forma ASÍNCRONA. Podemos ver cómo gestionar las funciones asíncronas aquí: Funciones asíncronas en JavaScript: Promises y Async/Await.

Cómo acceder desde componentes (Composition API)

Se hará como hemos visto en el apartado anterior, pero debemos importar useStore y definirnos una variable store:

Bloque de código
languagejs
<script setup>
import { useStore } from 'vuex';

const store = useStore();
</script>

Después, se accede de igual manera, pero en vez de a través de this.$store, a través de store.


Acceder desde archivos JavaScript

...

Bloque de código
languagejs
import store from "../store"

store.getters["token/isLogged"];
store.dispatch("modulo/action", parametro);


Persistir estado

Advertencia

Este plugin guarda la parte del estado que indiquemos en el local storage del navegador, es decir, se queda accesible, por lo que debemos asegurarnos de no guardar nada de información sensible.

Para que el estado sea persistente cuando se refresque la página, utilizamos vuex-persistedstate, en concreto el plugin createPersistedState().

Para esto, en primer lugar nos descargamos el paquete de npm:

...

Después, como hemos visto antes, podemos especificarlo en la sección plugins de nuestro store (en el index.js, en los módulos no funciona):

Bloque de código
languagejs
import createPersistedState from "vuex-persistedstate";

...
...,
  // Para hacer que el estado persista tras refrescar la página
  plugins: [createPersistedState()]
})

...

Bloque de código
languagejs
// Persistir todo. No se puede utilizar en módulos, sólo en la definición del store general
createPersistedState()

// Persistir un módulo con el nombre que tengamos especificado en el bloque de modules, también sólo en el store general
createPersistedState({ paths: ["modulo"] })

// De la misma forma, podemos persistir las variables del state por su nombre, y esto se puede poner también dentro de los módulos
createPersistedState({ paths: ["variableState"] })

// Desde el store general, podemos persistir ciertas partes de los módulos de esta forma
createPersistedState({ paths: ["modulo/.variableState"] })