Vuex es una libreria para aplicaciones Vue.js. Sirve como una tienda centralizada de datos para todos los componentes de una aplicación.

¿Por qué usar Vuex?

Cuando se desarrolla una aplicacion de mediana o gran escala con vue suelen haber ciertas complicaciones cuando se trabaja con muchos componentes y es que la manera de compartir y enviar informacion entre padre, hijo y el resto de componentes se vuelve una tarea bastante dolorosa. Pero no te preocupes Vuex llega al rescate.

Estructura

Estado (state):

  • Es un objeto que puede contener cualquier tipo de información: strings, arrays u otros objetos.
  • Es la información que almacenamos de forma centralizada en toda la app.
const app = new Vue({
  el: '#app',
  // provide the store using the "store" option.
  // this will inject the store instance to all child components.
  store,
  components: { Counter },
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})

Getters (getters):

  • Son funciones que devuelven variables del state.
  • No cambian el estado pero sí formatean la información para que podamos utilizarla de la manera que la necesitemos.
  • Funcionan tal cual como en POO.
const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})

Mutaciones (mutations):

  • Son funciones que pueden modificar el state.
  • Son síncronas.
  • Se pueden inicializar en el componente a utilizar a través de commit o inicializarse a través de una acción.
const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // MUTANDO EL ESTADO
      state.count++
    }
  }
})

Acciones ( actions):

  • Son funciones asíncronas.
  • Poseen la lógica de negocio que cambiar el state y deben de llamar a mutations a través de commit.
  • La forma de inicializarse en el componente es a través de dispatch o utilizando modulos.
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      // posee acceso completo al state
      state.count++
    }
  },
  actions: {
    increment (context) {
      // context hace referencia al store
      // para llamar a las mutations
      context.commit('increment')
    }
  }
})

MODULES & NAMESPACES

Los módulos en Vuex nos ayudan a separar lógica de negocio a medida que nuestra aplicación va creciendo de esta manera nos segura que el store se mantenga ordenado, código legible y escalable.

Mientras que namespaced: true le indica a Vuex que tome el nombre del módulo para no caer en ambigüedades cuando llamamos a alguna variable del state con el mismo nombre dentro de otro módulo.

const product = {
  namespaced: true,
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const user = {
  namespaced: true,
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    product
    user
  }
})

store.state.product // -> `product`'s state
store.state.user // -> `user`'s state

¿Cómo acceder al STORE?

Existen muchas maneras de acceder nuestra tienda de datos ya sea de manera global a traves de $store o por medio de importación de los módulos mapState, mapGetters, mapMutations, mapActions desde Vuex.  Cual sea la opción que utilicemos no debemos olvidar llamar al módulo correspondiente si estamos usando namespaces. Aquí les dejo un ejemplo sencillo comparativo de ambas maneras de acceder al state.

MyComponent.vue

<template>
    <!-- de manera GLOBAL a traves del $store -->
    <h1>{{$store.state.user.name}}</h1>
    
     <!-- via computed properties -->
    <h1>{{name}}</h1>
</template>

<script>
// por medio de importación desde Vuex
import { mapState, mapGetters } from 'vuex'
export default {
    ...
    computed: {
      // getters y state pueden mezclarse aqui para matchear sus cambios
      ...mapState("user", ["name"]),
      ...mapGetters("product", ["productsAvailable"])
    },
    methods: {
    	changeUserName(name) {
            // llamando una mutation para cambiar 
            // el nombre del usuario
            this.$store.commit('user/CHANGE_NAME', name)
        }
    
    }
    mounted() {
        // llamando un action para cargar los productos 
    	this.$store.dispatch('products/fetchProducts')
    }
    ...
}    
</script>
"Las bibliotecas de flujo son como gafas: sabrá cuándo las necesita".
Dan Abramov, autor de Redux.