Easy Data Flow with Vuex

Nicolas Del Valle

Full Stack Developer en E-xact Transactions​​

Qué es Vuex?

Patrón de gestión de estados + biblioteca

Inspirado en Flux, Redux y la Arquitectura Elm

  • Store centralizado
  • Reglas para mutar el estado

Qué es Flux?

Arquitectura para la construcción de interfaces de usuario

Más que un framework es un patrón

Por qué?

Facebook encontró problemas aplicando el Modelo Vista Controlador en aplicaciones de gran escala

Qué propone?

Los datos de una aplicación Flux fluyen en una sola dirección (Unidirectional data flow)

Se enfoca en crear flujos de datos explícitos y entendibles

Flujo Unidireccional en componentes Vue

new Vue({

  // State: Fuente de verdad que impulsa nuestra aplicación
  data () {
    return {
      count: 0
    }
  },

  // View: Representación del estado
  template: `
    <div>{{ count }}</div>
  `,

  // Actions: Posibles formas en que el estado podría cambiar en reacción a las
  // interacciones del usuario con la vista
  methods: {
    increment () {
      this.count++
    }
  }
})

 Simple representación usando un componente

 Representación usando varios componentes

Flujo Unidireccional en componentes Vue + Vuex

 Representación usando varios componentes

Implementación Inicial

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment: state => state.count++,
    decrement: state => state.count--
  }
})

new Vue({
  el: '#app',
  computed: {
    count () {
      return store.state.count
    }
  },
  methods: {
    onIncrement () {
      store.commit('increment')
    },
    onDecrement () {
      store.commit('decrement')
    }
  }
})
<div id="app">
  <p>{{ count }}</p>
  <p>
    <button @click="onIncrement">+</button>
    <button @click="onDecrement">-</button>
  </p>
</div>

Ejemplo Básico

Inyección del Store en todos los componentes

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>
  `
})
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count
    }
  }
}

Conceptos Core

(State, Getters, Mutations, Actions)

State

  • Un State por aplicación (single source of truth)
  • Cantidad variable de información
  • Componentes pueden seguir teniendo su State local

Getters

  • Propiedades computadas del State
  • Como las propiedades computadas de un component, usa un sistema de cache

Uso de Getters

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)
    },
    // Getters will also receive other getters as the 2nd argument
    doneTodosCount: (state, getters) => {
      return getters.doneTodos.length
    }
  }
})
const TodosComponent = {
  computed: {
    todos () {
      return this.$store.state.todos
    },
    doneTodos () {
      return this.$store.getters.doneTodos
    }
   }
}

Mutations

  • La única manera de modificar el State en un Vuex Store
  • Se ejecutan a partir de un commit del Store
  • Operaciones sincronas unicamente

Uso de Mutations

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state, payload) {
      state.count += payload.amount
    }
  }
})
store.commit('increment', {
  amount: 10
})

store.commit({
  type: 'increment',
  amount: 10
})

Actions

Similares a las Mutations a excepción de:

  • En vez de mutar el estado las acciones comitean mutations
  • Pueden ser operaciones asincronas

Uso de Actions

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
    incrementAsync ({ commit }) {
      setTimeout(() => {
        commit('increment')
      }, 1000)
    }
  }
})
// dispatch with a payload
store.dispatch('incrementAsync', {
  amount: 10
})

// dispatch with an object
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

Cuándo usar Vuex?

Flux libraries are like glasses: you’ll know when you need them.

 

Dan Abramov

Demo

Easy Data Flow with Vuex

By Nicolas Del Valle