-
Notifications
You must be signed in to change notification settings - Fork 232
Vuex
In this section of the tutorial we'll look at central state management with Vuex (also known as the central store
or storage)...
$ npm install vuex --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
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]
})
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 }