Vuex, Flux for Vue.js

data management in Vue.js apps

As is

Is this a problem ?

Possible Solutions

 Store pattern

Global event bus

import Vue from 'vue';

let bus = new Vue();

export default bus;

import bus from '../../Shared/EventBus.vue';

// in component A:

bus.$on('some-event', callback)

// in component B:

bus.$emit('some-event')

EventBus

Components

Flux architecture

Flux is an architecture that Facebook uses internally when working with React. It is not a framework or a library. It is simply a new kind of architecture that complements React and the concept of Unidirectional Data Flow.

Vuex

flux for vue.js

What is Vuex?

Vuex is a state management pattern + library for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion.

image source mazarin.lk

Installing vuex

<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>
npm install vuex --save
yarn add vuex

Vuex parts

Vuex Store

 

import Vuex from ‘vuex

 

const store = new Vuex.Store({

  state: {…},

  getters: {…},

  mutations: {…},

  actions: {…}

})

 

new Vue({

  store, render: h => h(App)

}).$mount('#app')

Vuex - State

Vuex uses a single state tree - that is, this single object contains all your application level state and serves as the "single source of truth". This also means usually you will have only one store for each application.

Vuex - State

import Vuex from 'vuex'
const store = new Vuex.Store( {
  state: {
    todos: []
   }
})
const app = new Vue({
  el: '#app',
  store 
})

Vuex - Getters

The mapGetters helper simply maps store getters to local computed properties.

You can think of Getters as computed properties for stores.

Getter's result is cached based on its dependencies, and will only re-evaluate when some of its dependencies have changed.

Vuex - Getters

const store = new Vuex.Store({
  state: {},
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }}})
import { mapGetters } from 'vuex'

export default {
  computed: {  ...mapGetters(['doneTodos'])
  }}

Vuex - Mutations

The only way to actually change state in a Vuex store is by committing a mutation.

Vuex mutations must be synchronous!

Vuex - Mutations

const store = new Vuex.Store({
  mutations: { 
    increment (state, n){
      state.count += n
    }
  }
})
this.$store.commit('increment', 10)

Commit with Payload

Vuex - Mutations

Committing Mutations in Components

You can commit mutations in components with this.$store.commit('xxx'), or use the mapMutations helper which maps component methods to store.commit calls

import { mapMutations } from 'vuex'

export default {
  methods: {
    ...mapMutations(['increment')]
}

Vuex - Mutations

When we mutate the state, Vue components observing the state will update automatically.

1. Prefer initializing your store's initial state with all desired fields upfront.

2. When adding new properties to an Object, you should either:

 

   Use Vue.set(obj, 'newProp', 123),

     or

   state.obj = { ...state.obj, newProp: 123 }

Vuex - Actions

Actions are similar to mutations, the differences being that:

  • Instead of mutating the state, actions commit mutations.
  • Actions can contain arbitrary asynchronous operations.

Action handlers receive a context object which exposes the same set of methods/properties on the store instance, so you can call context.commit to commit a mutation, or access the state and getters via context.state and context.getters

Vuex - Actions

const store = new Vuex.Store({
  state: {count: 0},
  mutations: {
   increment (state) {
      state.count++
    }
  },
  actions: {
   increment (context) {
     context.commit('increment')
    }}
})

Vuex - Actions

this.$store.dispatch('incrementAsync')

Dispatching Actions

We can perform asynchronous operations inside an action.

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

Vuex - Actions

Dispatching Actions in Components

You can dispatch actions in components with this.$store.dispatch('xxx'), or use the mapActions helper which maps component methods to store.dispatch calls

import { mapActions } from 'vuex'

export default {
methods: {
    ...mapActions(['increment')]
}

Vuex - Modules 

Vuex - Plugins 

Vuex - Testing 

maybe next time ...

Vuex - Form Handling 

Vuex recap

const store = new Vuex.Store({

 

  state: {…}, // absolute truth

 

  getters: {…},

 

  mutations: {…}, // sync

 

  actions: {…} // async

 

})

mapState

mapGetters

mapMutations

mapActions

inside components

Thank you

@imhotepp

Q&A