Skip to content
David Graham edited this page Jun 26, 2018 · 9 revisions

In this section of the tutorial we'll look at central state management with Vuex (also known as the central store or storage)...

Install Vuex

$ npm install vuex --save-dev

Install vuex-router-sync --save-dev

Vuex-router-sync will help us get the current routing information from the store for each route we are currently on:

$ npm install vuex-router-sync

Modules

We will break up all of our storage using modules so that it is not all loaded initially to reduce app load size. Each feature in our app will have its own storage module (loaded async after the initial app loads, or once the feature is first accessed). The only two modules we need to load initially are the common and auth modules since these are cross-cutting.

The common module holds all our storage objects we need for cross-feature communication:

src/store/common.js

// Common State.
const defaults = {
  sidebar: {
    visible: true
  },
  title: '',
  layout: 'DefaultLayout',
  dialog: {
    visible: false,
    text: ''
  },
  snackbar: {
    visible: false,
    text: '',
    timeout: 6000,
    color: ''
  },
  error: {
    code: null,
    level: null,
    message: ''
  }
}

// Global module loaded on first app load.
export default {
  namespaced: true,

  state: Object.assign({}, defaults),

  mutations: {
    updateSidebar (state, options) {
      state.sidebar = Object.assign({}, defaults.sidebar, options)
    },

    updateTitle (state, title) {
      state.title = title
    },

    updateLayout (state, layout) {
      state.layout = layout
    },

    updateDialog (state, options) {
      state.dialog = Object.assign({}, defaults.dialog, options)
    },

    updateSnackbar (state, options) {
      state.snackbar = Object.assign({}, defaults.snackbar, options)
    },

    error (state, options) {
      state.error = Object.assign({}, defaults.error, options)
    },

    clear (state) {
      state = Object.assign({}, defaults)
    }
  },

  actions: {
    clear ({ state, commit, rootState, dispatch }) {
      commit('clear')
      dispatch('auth/clear', {}, { root: true })
    },

    updateSidebar ({ commit }, options) {
      commit('updateSidebar', options)
    },

    updateTitle ({ commit }, title) {
      commit('updateTitle', title)
    },

    updateLayout ({ commit }, layout) {
      commit('updateLayout', layout)
    },

    updateDialog ({ commit }, options) {
      commit('updateDialog', options)
    },

    updateSnackbar ({ commit }, options) {
      commit('updateSnackbar', options)
    }
  }
}

You'll notice we are typically using actions for everything. We use mutations within the actions to actually make the changes to the store underneath, but actions give us an abstraction (we can capture more logic) and async ability over the mutations. For example, in the clear action we clear the common storage and then call the auth module's clear action so that the auth data is also cleared.

You can visit the Auth section of this wiki to learn more about the auth storage module.

Now add the module to Vuex from our index file:

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import auth from '@/auth/store'
import common from './common'
import localStoragePlugin from './plugins'

Vue.use(Vuex)

export default new Vuex.Store({
  modules: { common, auth },
  plugins: [localStoragePlugin]
})

Plugins

We'll want some state to be available across browser tabs (and when the app is closed/reopened) so let's sync this state with LocalStorage. When the app bootstraps, we want to first check in the browser's localStorage and retrieve all of our previously stored data (we don't need to keep all data from Vuex synced to LocalStorage, but certain data we may want preserved). This syncing can be accomplished using plugins:

src/store/plugins.js

import Vue from 'vue'
import Vuex from 'vuex'
import auth from '@/auth/store'
import * as constants from '@/constants'

Vue.use(Vuex)

// Sync with local storage.
if (localStorage.getItem(constants.STORAGE_KEY)) {
  const syncedState = JSON.parse(localStorage.getItem(constants.STORAGE_KEY))
  auth.state = syncedState.auth ? Object.assign(auth.state, syncedState.auth) : auth.state
}

// LocalStorage plugin.
const localStoragePlugin = store => {
  store.subscribe((mutation, state) => {
    const syncedData = { auth: state.auth }

    localStorage.setItem(constants.STORAGE_KEY, JSON.stringify(syncedData))

    if (mutation.type === 'common/clear') {
      localStorage.removeItem(constants.STORAGE_KEY)
    }
  })
}

export { localStoragePlugin }

Clone this wiki locally