Vue: Using localStorage with Vuex store
ByMike Street
This tutorial uses Vue v2.4.4 and Vuex v2.5.0 - although I'm sure it will work with previous versions
localStorage basics
localStorage
is a cache in the browser which persists even after the browser is closed. It allows you to store data on a page and later access it - it's especially easy to do using JavaScript. More information aboutlocalStorage
can be found on theMDN Website, but the basics are as follows. Thekey
is an identifiable string for you to access the saved data later.
// Store the "value" under the ID of "key"localStorage.setItem('key','value');// Load the data back and store as a variablelet val= localStorage.getItem('key');// val will equal "value"
Note:
localStorage
canonly contain strings. This means that any objects or arrays you wish to store inlocalStorage
must be converted to a JSON string, and then re-formatted when you retrieve them.
For example:
// Convert the object into a JSON string and storelocalStorage.setItem('key',JSON.stringify(object));// Retrieve the data and convert from JSOn string to object/arraylet obj=JSON.parse(localStorage.getItem('key'));
Vuex
Vuex is a centralised state management tool for Vue. It gives you a central store that all of your components can access, update and react to changes. Unless you are doing a very simple (in functionality) Vue app, it is highly recommended you use Vuex for all of the management of your data and states.
Using localStorage with Vuex
On the latest Vue app I'm developing, I wanted the Vuex contents (orstate
) to be stored inlocalStorage
whenever it was updated. This meant that at any time the user could close their browser and, when they return, have the app in the same state as when they left it. Be it products in the basket or user preferences, I wanted the app to remember what they had chosen.
Initialise the store
If you're reading this I would assume you've got your store already initialised. However you've built your app, thestore should have a variable assigned to it.
// Initialise your storeconst storenewVuex.Store({// You state might be more complex than thisstate:{count:1},mutations:{},getters:{}});
Storing data
We now wish to cache the data whenever the store updated. Fortunately, Vuex offers asubscribe
function which triggers whenever the store updates.
After your store has been initialised, register the subscribe method on yourstore
variable. This function accepts two parameters - the mutation which was fired and the stateafter the mutation. We wish to store this state in ourlocalStorage
. AslocalStorage
is specific to each domain name, we can use a variable name to reference the contents - such asstore
. Don't forget to convert your object to a string.
// Subscribe to store updatesstore.subscribe((mutation, state)=>{// Store the state object as a JSON stringlocalStorage.setItem('store',JSON.stringify(state));});
Retrieving data
With our data now stored with every update, we need to retrieve the data on page load. When the user re-accesses the app, we need to replace the existing, empty store with the contents of our storage.
To do this, we are going to create a mutation within the store, which updates the state, and trigger this when the app is created.
Create a new mutation calledinitialiseStore
. Inside this mutation, check if thelocalStorage
item exists
const storenewVuex.Store({state:{count:1},mutations:{initialiseStore(state){// Check if the ID existsif(localStorage.getItem('store')){}}},getters:{}});
We now need to replace the current state if it does exist. To do this, we are going to use thereplaceState
Vuex method. Within here, we are going to merge both the current, blank, state and the stored data. The reason for this is so that if there are any new properties which were added since the last time the user visited, they don't get any dreadedundefined
errors.
const storenewVuex.Store({state:{count:1},mutations:{initialiseStore(state){// Check if the ID existsif(localStorage.getItem('store')){// Replace the state object with the stored itemthis.replaceState(Object.assign(state,JSON.parse(localStorage.getItem('store'))));}}},getters:{}});
The last stage is to call this mutation when the Vue app is created. We want this to happen at theearliest point which, based on theVue lifecycle hooks is during thebeforeCreate()
method.
Add this method to your Vue instance and trigger the mutation:
newVue({el:'#app',store,beforeCreate(){this.$store.commit('initialiseStore');}});
Huzzah! You now have an app with a Vuex store cached inlocalStorage
.
If you found this post useful I would appreciate if you consideredchucking a couple of quid my way. Thanks!
Update 20/10/17
Cache Validity
While using this in a project recently, I experienced an odd sensation where changes I made were not being reflected. This is because I had altered thestore
structure without clearing mylocalStorage
. Adding values was fine, but renaming, editing or altering a value's type did not change.
Although not an issue for me, as I can clear the cache, if some code were to be pushed live, this could affect users who had visited the site before.
Fortunately, I was usingsemver for my versioning (and even if you're not - this will work as long as you version each release somehow) and so I could call upon ver version number to check if the store was up to date.
If on load, the user had the same version number as that of my app, then the cache was fine. If it's different, clear the cache and load a new version.
Be warned This will clear thewhole cache, so if you are relying on it for user preferences or similar, you may wish to do the selective deletion.
The first step is to load our version number. Ours is stored in thepackage.json
so, using ES6, this is as simple as:
import{version}from'./package.json';
However, you may wish to cache yours from a git tag or have it somewhere as a variable. Ideally, it needs to be accessed separately from the store so that the cache doesn't end up overwriting it.
Next, create an empty string in your store - for the version to be saved once verified.
state:{// Cache versionversion:'',count:1},
We can now update ourinitialiseStore
mutation to check the version with that of the one in the cache and take appropriate action based on the result
initialiseStore(state){// Check if the store existsif(localStorage.getItem('store')){let store=JSON.parse(localStorage.getItem('store'));// Check the version stored against current. If different, don't// load the cached versionif(store.version== version){this.replaceState(Object.assign(state, store));}else{state.version= version;}}}
Update 25/10/17
Selective Caching
You may only wish to cache a few elements from your store, this can be achieved by creating a new object in yoursubscribe
function and storing that. We are already merging the cache with the current store state on load, so that doesn't need to change.
store.subscribe((mutation, state)=>{let store={version: state.version,count:1};localStorage.setItem('store',JSON.stringify(store));});
Links
You might also enjoy…
- Using props for accessing URL parameters within components with Vue Router (video)
21st October 2017
Using props for accessing URL parameters within components with Vue Router (video)
This quick video walkthrough shows how you can replace any URL parameters in your components with props and how to pass them through from vue router to access them within your component
- How can I verify my Google Event Tracking is working?
18th September 2017
How can I verify my Google Event Tracking is working?
Validating your Google Event tracking is working can be a tricky business. This blog post walks you through checking the data being sent to Google Analytics, so you can verify the information is correct.

Written byMike Street
Mike is a CTO and Lead Developer from Brighton, UK. He spends his time writing, cycling and coding. You can find Mike onMastodon.