Skip to content

Instantly share code, notes, and snippets.

@MaxMonteil
Last active February 9, 2020 22:10
Show Gist options
  • Save MaxMonteil/8b8b3b5a999611520e789772620ce498 to your computer and use it in GitHub Desktop.
Save MaxMonteil/8b8b3b5a999611520e789772620ce498 to your computer and use it in GitHub Desktop.
# Client-Side Storage with Vue
Keep your user's data available with or without a connection using Vue and LocalStorage.
## No Internet, No Problem
The web is undoubtably an amazing platform enabling people to communicate, share, and experience things in insane ways that weren't possible until recently. As web-developers, we have the honor of creating such experiences.
The internet is great but only if you can access it. When you can't, user's shouldn't be permanently deprived of it's services. One way to solve this is by using Client-Side storage.
Client-Side storage enables users to access their data even when offline, it also serves the double purpose of speeding up interactions. With data stored locally, your site or app might not even need to send a server request and wait for a response.
A faster and more practical internet is our goal so let's look at one way to get there.
## What we will do
In a [previous article](https://medium.com/@mntlmaxi/dry-vue-how-to-reuse-and-prepopulate-forms-83068e142c70 "Dry Vue: How to reuse and prepopulate forms") we created a ToDo list app, it worked as expected but reloading the page would remove all the tasks we had set. We're going to look at one method of storing this information on the browser.
## Client-Side Options
There are a few ways to implement client-side storage each with it's pros and cons.
### LocalStorage
LocalStorage is one of the storage mechanisms in the Web Storage API that allows browsers to store information using key-value pairs. It is best suited for simple data values because it can only store strings. If you have to use LocalStorage for more complicated data you will have to parse it into JSON and back.
### IndexedDB
If you want to store more complex data, files, or even blobs in the browser IndexedDB is what you're looking for. It is also the database you would need when making a PWA.
IndexedDB is a transaction based database system that is described by MDN as _a JavaScript-based object-oriented database_. What this means is that data isn't stored in table with rows and columns as with SQL-based RDBMS but rather with Javascript objects that are accessible/indexed with a key.
[Read more at MDN](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)
---
For our ToDo app LocalStorage is more than enough so lets implement it.
## Setup
If you want to follow along git clone the proper todo list branch to get started.
https://gist.github.com/069381f17d8d41fa0ac723fe3aa27238
The final project is found at:
https://gist.github.com/b8000f21111cf5e1b520db43597957ec
## Adding LocalStorage
Actually adding localStorage to our todo app is incredibly simple and works in two steps.
The first step is to check localStorage for already exisiting data with which to fill our component (aka Read), the second step is to save the state of our todos into localStorage (aka Write).
To do this, we will use two of the methods offered by the localStorage API, `getItem` and `setItem`.
### Reading from Storage
In order load data into the component at the right moment, we will hook into the component lifecycle using `mounted`.
There, we check if localStorage has values associated with the 'todos' and 'completed' keys, it makes sense to use the key names as we do in our component data. We can actually take it a step further and have an extra value called `dataFields` which would hold the name of any future values we would like to store on the client.
In our checkStorage method we assume that any error means the data is corrupted and we can then simply remove it.
Another thing to keep in mind is that localStorage only accepts string values, for arrays and objects, we need to parse the data into JSON and back.
https://gist.github.com/27be4b21e53c848cb8a88dd7210a0db9
### Writing to Storage
Saving our todos is just as simple.
We will create a `saveTodos` method that will go through our useful `dataFields` array, stringify the data and store it.
What about edits?
To be aware that a todo has been edited we also need to emit an event from the `ListItem` component and listen to it in `TodoList`.
With that, all we need to do is call the method whenever we add, delete, edit, or complete a todo!
https://gist.github.com/cdacc5a1e29b384bbe2cfef9e378331a
## Taking things further
Now our todo app has persistent data, you can try it out by adding some tasks and reloading the page, you'll see that they're still present.
Making it work is only the start. There are actually a few extra things we could do to help make our app more maintainable, they might not make sense for a simple app such as this but in larger programs it is critical.
One thing to do is to decouple our obvious dependency on localStorage. Currently all the storage related code is right inside the componenent, if we ever want to switch to using IndexedDB it would require quite a bit of rewriting, it gets even worse if you also want to add calls to a server where more data is stored.
### Refactor refactor refactor
The first thing we will do is add Vuex to our app. It isn't absolutely necessary but it does set us up for whatever future changes we might go through. Vuex will help us separate concerns even more by ensuring components only deal with the data and actions that directly concern them.
Add vuex to the app with
https://gist.github.com/e97707c42e4a0837372907f218640ac4
Next we move the state and every method changing it from our component to the store.
The way I usually work with Vuex is to only dispatch actions from components. In the store these actions will then manage calls to mutations or other actions. To make this as practical as possible, I try to make my mutations simple and atomic so it often happens that an action will call a mutation multiple times with different arguments.
This works well since mutations are meant to only directly change the state and finish rather fast.
Of course this is just how I personally use it, with an application as simple as ours you can skip using actions all together.
### Abstract abstract abstract
The next step is to reduce our dependence on LocalStorage, or at least make it as painless as possible to change or even switch away from it.
To do that we'll create an `api/` folder with a `localStorageService.js` file. There we place all calls to localStorage from the store.
The advantage of this is whenever we want to change how localStorage behaves we can just make changes there, even better, if we decide to use something else, the other option only needs to export functions with the same signature.
https://gist.github.com/30a3493f2ac80c1b5648c0e8bf116288
You can get the code for that from this branch:
https://gist.github.com/2aa75cfdf159aeb9820e9174cfd1b9e5
## Conclusion
We've updated our todo app to now keep it's state saved even if the page reloads or if the user leaves and returns to it later. This also has the added benefit of not needing to make calls to a server each time the page loads.
Even more than that, we started future-proofing the app for future updates, our client-side storage option is super modular and components are nicely compartementalized.
Hopefully this helped you out in your own projects.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment