Skip to content
David Graham edited this page Jun 9, 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.

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. This syncing can be accomplished using plugins. Check out the plugin in our index file (you can move the plugin to its own file for a cleaner approach if you prefer):

src/store/index.js

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

Vue.use(Vuex)

/**
 * Key for local storage.
 *
 * Set the key to use in local storage to hold persistant data. If logged in,
 * you can see this key by going to Chrome > dev tools > application tab,
 * then choosing "Local Storage" and "http://localhost:8080".
 *
 * @type {string}
 */
const STORAGE_KEY = 'vue-pizza'

// Sync with local storage.
if (localStorage.getItem(STORAGE_KEY)) {
  const syncedState = JSON.parse(localStorage.getItem(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(STORAGE_KEY, JSON.stringify(syncedData))

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

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

Clone this wiki locally