Guía de Vuex - Administración de estado centralizada para aplicaciones Vue

En esta guía, veremos Vuex, la biblioteca de administración de estado centralizada para aplicaciones Vue. Aprenda a usar getters, acciones y mutaciones para alterar el estado de la tienda Vuex a través del código.

Introducción

Vuex es una biblioteca que almacena datos en una tienda Vuex, que actúa como fuente de datos sobre estados en una aplicación Vue. Este almacén contiene un estado global (conjunto de propiedades) y funciones (captadores, acciones y mutaciones) que se utilizan para leer y alterar el estado.

Considere un escenario en el que desea crear una aplicación Vue simple que le permita agregar o eliminar un valor de una variable, “recuento”, como en la imagen a continuación:

A simple counter application

El proceso normal sería: primero, definir una función que devuelva nuestra variable contar:

1
2
3
4
5
data() {
   return {
     count: 0
  }
}

Y luego defina una función de incremento y decremento para que podamos manipular el ‘recuento’:

1
2
3
4
5
6
7
8
methods: {
  increment() {
    this.count++;
  },
  decrement() {
    this.count--;
  }
}

Si bien no hay nada de malo con este patrón (al menos en aplicaciones simples), surge un problema cuando intentas compartir los datos entre diferentes componentes de forma reactiva.

Puede optar por usar los accesorios de los componentes, pero considerando un caso realista de trabajar con 50-100 (o más) componentes, el uso de los accesorios se volvería tedioso con bastante rapidez.

Compartir datos entre componentes se vuelve más complicado cuando se desarrollan aplicaciones a gran escala, es decir, aplicaciones con docenas de componentes. Es por eso que se crearon soluciones como Vuex, para hacer que la gestión estatal sea menos dolorosa.

En esta guía, repasaremos todo lo que necesita saber para comenzar con la biblioteca de administración estatal oficial de Vue.js, Vuex.

Primeros pasos con Vuex {#empezando convuex}

Vuex se inspiró en proyectos como Flux de Facebook y State Management Library de React, Redux, para hacer que almacenar e intercambiar datos reactivos en su aplicación Vue sea lo más simple posible mientras asegurando el rendimiento y la mantenibilidad.

Esto se logra al tener un almacenamiento centralizado del que se extraen datos y en el que se escriben datos. No hay otra forma de obtenerlo o alterarlo, haciéndolo consistente y estable en muchos componentes. Esto elimina la inestabilidad que a menudo se puede causar cuando varios componentes reactivos se comunican entre sí.

Según su documentación:

"Vuex es un patrón de administración de estado + biblioteca para aplicaciones Vue.js. Sirve como un almacén centralizado para todos los componentes de una aplicación, con reglas que garantizan que el estado solo se puede cambiar de manera predecible."

Esto se logra a través de tres tipos de métodos, que operan en el estado grabado. Los captadores se utilizan para obtener datos del almacén, las acciones se utilizan para obtener datos de forma asincrónica, procesarlos e invocar mutaciones, y las mutaciones se utilizan para cambiar los datos de origen en el almacén. En cierto sentido, puedes imaginar un ciclo de:

Vuex request lifecycle

El estado global centralizado (o propiedad del mismo) se muestra al usuario a través de captadores -> la aplicación invoca una acción -> la acción invoca una mutación en el estado global -> los captadores se utilizan para recuperar el nuevo estado y mostrarlo al usuario

A través de estos elementos, puede realizar una gestión de estado estable y mantenible.

Instalación de Vuex {#instalación de Vuex}

Hay varias formas de instalar Vuex; la mayoría de ellas dependen de cómo haya creado su aplicación vue.

{.icon aria-hidden=“true”}

Nota: Si ya está familiarizado con el proceso de instalación de Vuex, puede omitir esta sección e ir a la sección Gestión de estado centralizada con Vuex.

Si su proyecto utiliza Vue CDN en lugar de herramientas descargadas como vue-cli o vite, querrá descargar el archivo fuente de Vuex e incluir en el marcado de su aplicación:

1
2
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>

Si está utilizando vue-cli, puede incluir directamente paquetes oficiales de Vue como vue-router y vuex durante el proceso de instalación.

Primero, querrás crear un nuevo proyecto Vue:

1
$ vue create project-name

Ejecutar esto debería mostrar el siguiente resultado:

vue-cli output

Desde aquí, puede usar su teclado para navegar a la opción Seleccionar funciones manualmente, para agregar todos los paquetes que necesitará su aplicación, incluido Vuex:

vue-cli process

Alternativamente, si tiene un proyecto existente creado usando vue-cli o Vite que no tiene soporte previo para Vuex, puede instalarlo con npm o yarn:

1
2
3
$ npm install vuex --save
# Or yarn
$ yarn add vuex

Configuración Vuex

Si instaló Vuex como un paquete con yarn o npm, debe indicar explícitamente a Vue que lo use como complemento:

1
2
3
4
5
6
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

new Vue({...})

Administración de estado centralizada con Vuex {#administración de estado centralizada con vuex}

La Tienda es el centro de todas las operaciones en una aplicación Vuex. Es un contenedor reactivo que contiene el estado de toda su aplicación, así como las funciones necesarias para leer y escribir en este conjunto de estados. Además, los datos o métodos definidos en una tienda son universales, lo que significa que puede acceder a ellos desde cualquier lugar de su aplicación vue.

Podemos crear fácilmente una nueva tienda Vuex inicializándola usando el Vuex importado:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {},
  mutations: {},
  actions: {},
  getters: {}
});

Mientras está vacío, la tienda solo tiene una colección de estados vacíos, mutaciones, acciones y captadores. ¡Podemos acceder a esta instancia de tienda a través de una instancia global this.$store! Aunque, antes de acceder a él, querremos registrarlo en nuestra instancia de Vue:

1
2
3
4
new Vue({
  el: '#app',
  store: store,
})

¡Ahora, podemos llenar la tienda con estados y funciones que la harán útil para nosotros!

Estado de Vuex

Considere que el estado de Vuex es el equivalente de datos en una instancia de Vue. Sin embargo, a diferencia de los datos, todo lo que almacena en un estado es global, lo que significa que no está restringido a un solo componente y se puede acceder a él o modificarlo en cualquier parte de su aplicación.

Puede agregar entradas al estado simplemente agregando propiedades al campo estado de la instancia de la tienda:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const store = new Vuex.Store({
  state: {
    name: "John Doe",
    age: 12,
    details: {
      city: "San Fransisco",
      country: "USA",
    },
  },
});

Aquí, definimos un estado para nombre de usuario, edad y detalles (un objeto que contiene la ciudad y el país del usuario). ¡Estas propiedades del estado ahora son accesibles globalmente!

Por lo general, definiría algunas constantes globales aquí.

Acceso a estados de Vuex {#acceso a estados de Vuex}

La forma más sencilla de recuperar un valor de estado es devolver el estado desde dentro de una propiedad calculada. Digamos que queremos acceder al estado global name y age en nuestra tienda:

1
2
3
4
5
6
7
8
computed: {
  name() {
      return this.$store.state.name;
    },
  age() {
     return this.$store.state.age;
    },
}

{.icon aria-hidden=“true”}

Nota: Declarar todas estas propiedades calculadas puede volverse tedioso y detallado cuando un componente necesita acceder a varios estados de almacenamiento. ¡Hay una clase de ayuda creada solo para eso que cubriremos en un minuto!

Por supuesto, ahora se puede acceder a estos valores en nuestro marcado:

1
2
3
4
5
6
<template>
  <div id="app">
    <p>Name: {{ name }}</p>
    <p>Age: {{ age }}</p>
  </div>
</template>
El ayudante de mapState()

La declaración de propiedades calculadas, como se ve en el ejemplo anterior, puede ser muy larga. Anticipándose a esto, Vuex se envía con un ayudante para generar funciones getter calculadas. Es un mapeador de estado y le permite mapear fácilmente estados calculados a alias más cortos.

Por ejemplo, importemos la función auxiliar mapState() y asignemos state.name y state.age a alias más cortos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// First - import mapState
import { mapState } from "vuex";

export default {
  name: "ComponentName",
  computed: mapState({
    name: (state) => state.name,
    age: (state) => state.age,
  }),
};

Funciones captadoras {#funciones captadoras}

Las funciones getter son funciones que se utilizan para obtener una propiedad calculada de una tienda. Al obtener una propiedad, puede optar por filtrar, validar o manipular adicionalmente los datos si es necesario, antes de devolverlos.

{.icon aria-hidden=“true”}

Nota: Los captadores se utilizan solo para obtener datos y no para modificar la fuente original. Si bien puede filtrar y manipular lo que le devuelve al usuario, no debe cambiar la fuente original en el lugar.

Por ejemplo, supongamos que hay un estado que realiza un seguimiento de los números enteros. A través de una función getter, puede devolver los números tal como son, o ordenarlos y separar algún número de ellos para devolver:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const store = new Vuex.Store({
  state: {
    myNumbers: [11, 3, 5, 1, 54, 56, ...],
  },
  getters: {
    firstFiveSorted: (state) => {
      return state.myNumbers.sort().slice;
    },
  },
});

Este getter ahora está disponible en el objeto global store.getters y también se puede acceder a él desde cualquier componente:

1
2
3
4
5
6
//...
computed: {
  firstFiveSorted () {
    return this.$store.getters.firstFiveSorted
  }
}

Sin embargo, esto también se vuelve detallado después de un tiempo. Al igual que puede asignar estados a sus alias, también puede asignar captadores a sus propios alias, a través de una función auxiliar mapGetters():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import { mapGetters } from "vuex";

export default {
  computed: {
    ...mapGetters({
      // this example will map `myNumbers` to `this.$store.getters.firstFiveSorted`
      myNumbers: "firstFiveSorted",
    }),
  },
};

Mutaciones de Vuex {#mutaciones de Vuex}

En Vuex, la única forma de modificar un estado de origen es a través de mutaciones. Puede pensar en ellos como la propiedad métodos en una instancia de Vue, pero sirven para modificar un estado en una tienda Vuex. Además, las mutaciones se llevan a cabo a través de la tienda, para garantizar que los cambios sean predecibles.

{.icon aria-hidden=“true”}

Nota: Por convención, los nombres de las mutaciones se escriben en mayúsculas y se estilizan con SNAKE_CASE.

Las mutaciones recibirán el estado como primer argumento y una carga útil opcional (es decir, argumentos opcionales necesarios para cometer la mutación) como segundo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const store = new Vuex.Store({
  state: {
    myNumbers: [11, 3, 5, 1, 54, 56]
  },
  mutations: {
    ADD_NUMBER(state, numberToAdd) {
      state.myNumbers.push(numberToAdd);
    },
  }
})

Y, para invocar una mutación, necesitaremos llamar al método store.commit() con el nombre de la mutación y su carga útil, si existe una carga útil:

1
this.$store.commit('ADD_NUMBER', 75);

La única forma de llamar a las mutaciones es confirmar un cambio en la tienda, pasando el nombre de la mutación.

{.icon aria-hidden=“true”}

Nota: Una desventaja de las mutaciones es que deben ser síncronas, es decir, no puede realizar una operación asíncrona dentro de ellas. Las acciones de Vuex son una solución a esto, que discutiremos en la siguiente sección.

Acciones

Las acciones se utilizan para obtener y procesar datos antes de que una mutación confirme ese cambio. Además, puede realizar de forma asíncrona múltiples llamadas de mutación a través de acciones, mientras que las mutaciones en sí se ejecutan de forma síncrona. Además, las acciones pueden llamar a otras acciones, a diferencia de las mutaciones que deben invocarse a través del método commit().

En cierto sentido, puede pensar en las acciones como agentes habilitadores para mutar datos, donde las mutaciones hacen el trabajo pesado final.

Las acciones reciben un objeto de contexto y una carga útil opcional como su parámetro. El objeto de contexto proporciona acceso a métodos como context.commit(), que le permite cometer una mutación. context.state() y context.getters() le permiten acceder al estado y captadores de la tienda. El objeto context no es la instancia de la tienda, simplemente expone las mismas propiedades que la instancia de la tienda.

Por ejemplo, digamos que queremos realizar una operación asíncrona que agrega un número aleatorio a la matriz myNumber cada n segundos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
const store = new Vuex.Store({
  state: {
    myNumbers: [11, 3, 5, 1, 54, 56, "..."],
  },
  mutations: {
    ADD_RANDOM_NUMBER(state) {
      // Push a random number to `myNumbers` array
      state.myNumbers.push(Math.floor(Math.random() * 10));
    },
  },
  actions: {
    // Using destructuring to extract only `commit()` from the `context` object
    addNumber({ commit }, time) {
      setInterval(() => {
        commit("ADD_RANDOM_NUMBER");
      }, time * 1000);
    },
  },
});

Para invocar la acción en sí, también llamamos a la tienda para que lo haga, a través de la función dispatch():

1
store.dispatch('ADD_RANDOM_NUMBER', 10);

Pasar por la tienda garantiza que el estado solo cambie de manera predecible.

Conclusión

En esta guía, hemos echado un vistazo a Vuex: la tienda de gestión estatal oficial de Vue.

La Tienda Vuex es una colección de estados, captadores, mutaciones y acciones. Los estados se usan para definir propiedades de estado globales, mientras que los captadores se usan para obtenerlos. Puede asignar propiedades de estado y captadores a alias más cortos para que sea más fácil hacer referencia a ellos. Las mutaciones y las acciones trabajan de la mano para alterar las propiedades del estado de manera controlada.

¡Con esto, puede aplicar Vuex a su próximo proyecto Vue!