RadDevon

Use localStorage in Vue.js

Video Notes

In this video, we’re going to use localStorage to persist some user data in a Vue.js note-taking application.

We built this application from the ground up (well, almost) in my previous video. If you just want to watch this video to see how to implement localStorage in Vue, that’s fine too. Feel free to jump straight in.

Here are some resources that might help as you watch:

Thanks for watching the video! If you have questions, please comment on the video over on YouTube or mentioning me on Twitter.

Transcript

Hey everybody. This is Rad Devon. Last week we built a Vue.js app, a note-taking application, and this week we’re going to be returning to that to add persistence to it using local storage.

In case you weren’t here last week or in case you can’t remember what we worked on, I can totally identify with that, this is the Vue.js note- taking application we built last week. This is actually the application down here in the bottom pane. On the left hand side it’s got a list of note titles. On the right, when you create a note, it’s going to show the current selected notes. So this is a brand new note. That’s the title, and then we can tab into the contents. I can make multiple notes. I can switch between the notes. The currently selected note, it’s highlighted here in gray and displayed on the right. The problem is that if I refresh this, all of my data is gone.

You have several different options when it comes to persisting data in your web application. A lot of applications use databases to persist data. Those are really nice because you can attach the data to the user’s account and then when your user is on a different computer or maybe on their phone, they can still have access to the same data that they created on their desktop or their laptop computer.

The difficult part about the database is that then you have to have user authentication. You have to save accounts and passwords, and there are security concerns around that. So it gets complicated pretty quickly.

Local storage is a much simpler way to persist data. It lives on the user’s browser. So whatever computer it’s created on, that’s where the data stays. It is a key-value store inside the browser. And a key-value store just means that each piece of data has a key, which is just a name for that piece of data. And then it has a value, which is the data itself. So for something like this. We might store all the notes in a key called notes. And if we go to local storage and grab the notes key, then we’ll get back whatever we stored in it. Fortunately for this app, we don’t need data to travel with the user, so we’re just going to implement local storage. Let’s go do that now.

We only really need to do two different things to integrate local storage into our application. When the application loads, we need to look in local storage and see if anything is stored there. And when notes get updated in the application, we need to put those new notes into local storage.

Let’s start with the code we need to save our notes into local storage. In order to do this, we are going to create a watch on our Vue instance. That’s just a watch key which contains an object added to the object. We’re passing into the view constructor. Inside this watch object we’re going to create a method with the same name as the data attribute we want to watch. I want to do something when the notes value changes. So my method is going to be named notes. Vue is going to pass a value into this method when it calls it. And that’s going to happen anytime the notes data changes. The value that gets  passed inias just the new value for that data. So I’m going to call it new notes. Like I said, this method is going to be called every time the notes data is updated. So I need to ask myself, what do I want to do when that data gets updated?

The thing I want to do is I want to save the new value into local storage. I’m just going to save it in a key on local storage called notes. That’s specific line of code, line nine, there is nothing Vue about that. That’s just plain JavaScript. Local storage is an object that the browser gives me to work with. I can use it anywhere as long as I’m in a browser that supports local storage.

That takes care of saving my data. Now I need to load my data. To do that. I’m going to use a Vue lifecycle hook. This one is called mounted. This is just a method I add to the object I’m passing in the Vue constructor. What Vue does with it is when it hits that point in this Vue component’s life, it will call this method.

I’ll put a link in the description to the section of the Vue documentation that talks about lifecycle hooks. And if you scroll through this section, you’ll see a lifecycle diagram that tells you basically the stages of the life of a Vue instance. These red bubbles on the chart are lifecycle hooks. Those are points in the instances life that you can hook into and run your own code. You might have code that needs to run before the instance is created. Or when it is created. Or maybe before it is mounted, that means before it’s actually rendered. Or when it’s mounted. And to do any of that, you just add a method with that name, the name of the point in the lifecycle you want to hook into, to the object you pass into the Vue constructor. And Vue will call those methods when it reaches that point in the instances lifecycle.

We are going to load our notes out of local storage when this Vue instance is mounted. To do that, it’s pretty simple. First I’m going to check and see if there are any notes saved in local storage. If there are, I’m going to set the instance’s notes data to whatever we have and local storage for notes. We initialized notes as an otesempty array, but once the instance is mounted, if there is a value in local storage for notes, then it’s going to update that data value, which we can refer to here as this.notes with whatever value is in localsStorage .notes.

Let’s try this out and see if it works. I have a new note in the application. It should have been saved to local storage because we created a watch that looks at the notes data, so let’s refresh this and see if that note gets loaded back out of local storage.

It does not. So now we need to figure out why. To figure this out, I’m going to use Chrome’s developer tools. To pull that up on my Mac, I’ll use command-option-I, and on a Windows computer I would use control-shift-I. I have mine configured to show up on the right, and I have a dark color scheme. You might have a different color scheme and yours may be positioned differently on the window. Don’t sweat it. It’s still basically the same UI.

Chrome developer tools has a panel that will, let me look at the contents of local storage. So I’m going to start there. Let’s click this double arrow to get the rest of the panels. I need the application panel. I’m going to stretch this out a little bit more. In the sidebar on the left, I have all sorts of different things I can look at. I’m going to expand local storage. And to be honest, I wasn’t really sure which of these would have my data. So I started here, and I could see that neither of these was a key I was familiar with. So I clicked down to this one and I saw notes.  That is our data, but it doesn’t look right. It’s storing ”[Object  object]” instead of our actual notes.

The reason we’re getting this weird looking data in our local storage is because local storage doesn’t know how to handle arrays or objects. It doesn’t mean we can’t store arrays or objects. It just means we have to get those into some sort of data type that local storage can store. The only data type local storage can store is a string.

Let’s figure out how we can get our notes as a string before we try to put them into local storage. I’m finished with developer tools for now, so I’ll close that. I’m going to scroll down to my notes watch. This is going to be an array of notes. An array in JavaScript, just like basically everything, is just an object. So when we try to put new notes directly into localStorage.notes, it gets coerced into a string. JavaScript basically calls the two string method on the array, which gives you that ”[Object object]” value we saw in developer tools earlier.

We definitely want to turn this into a string, but we want to do it on our terms so that we can preserve the data. JavaScript has a JSON object and it has a couple of really handy methods. The first one is stringify that takes a JavaScript object and converts it into a string. And the second one is parse, which takes a string JavaScript object and turns it back into a real JavaScript object.

I’m going to use stringify here. That should get new notes into a format we can actually store in local storage. That’s not all though, because in order to continue working with the notes, once I load them out of local storage, I need them to be an object again. To take care of that, I will go up to my mounted hook and I’m not just going to load the value of local Storage.notes directly into the notes data. Instead, I’m going to parse that string back into a JavaScript object, first.

In order to test this, I need to clear all the data out of local storage. To do that, I will go back into Chrome developer tools, using command-option-I on the Mac or control-shift-I on Windows. It should drop you right back where we were, but if you need help getting there, it’s application, panel, local storage. And then just look at these two until you find the key you need, which is notes. We are going to hit this clear all button to clear all the data out. Now I will close dev tools and refresh.

You can refresh either by clicking the button next to the address bar or by pressing command-R on the Mac or F5  on Windows.

Our local storage is empty now. We can tell that because the app says no notes saved, which means our notes data attribute is just an empty array. Let’s try adding some notes.

Now we have a couple of notes. I’m going to refresh, command-R or F5. Okay. We sorta got it. The first note saved. I’m not quite sure why all the notes are not being saved. I expect they would have because I’m watching notes. When it changes, then the new contents of notes should get strengified and assigned to the local storage notes key.

Now I need to start debugging this problem. The first thing I’m going to do is I’ll go right here inside my notes watch, and I want to log something out to the console.

Debugging code is all about testing your assumptions. You think some code should work a certain way, but maybe it actually doesn’t work that way. What I believe is happening here is that every time we press a key into either the title field or the contents of a note. Our watch callback should be called.

I’m going to test that by logging a message out to the console every time that function is called, I’ll be able to look at either the code pin console or the Chrome developer tools console to see if I can see that message, and I can literally count how many times that message gets printed out to the console to determine how many times my watch callback ran.

What I’m going to do to test this is I’m going to add a title that should have called the notes watch several times. Since this field is bound to the current notes title, every time we type in that field, it’s changing the current note. Since the current note is in notes inside the Vue instance that should be triggering the watch each time. We will, just for simplicity’s sake, we’ll jump into this code pen console.

It looks like we have one log, but only one. Well, no, actually we have two, but we talked quite a few characters. I would have expected to see it more than that. Updated notes is not being output to the console as many times as I would expect.

That means we still have something wrong here. To figure out what it might be I’m going to reference the Vue documentation and just read up on the watch to make sure I understand exactly how those work.

I think I have found my answer in the documentation for the watch. You can provide the watch the way we did just by putting the method directly into the watch object. But there’s also a way you can add some additional options. One of those is deep. If I read up here on the deep option, it says, to also detect nested value changes inside objects, you need to pass in deep true in the options argument. That is what we need to do here because the value we’re changing is not the notes array itself. It is inside the notes array. We’re adding a value onto it, so that’s going to be for the purposes of this, a deep change.

Let’s flip back over to the app and implement that new option. The way I will do this, first, I’ll take out my console log. I don’t need that anymore. Instead of a notes method, I’m going to pass in a notes object. This is going to get a little messy for a second, but just bear with me and we’ll clean up later. The notes object needs a method that is handler, so we kind of just moved the handler one layer deeper.

Now we can also provide other options besides just the handler function to the notes watcher. The option we care about is deep and we need it to be set to true. Let’s try it out.

Okay. Two notes in memory. Let’s refresh and see if they get loaded. Code pens complaining that we haven’t saved our code. So we’ll do that and refresh.

There we go. Now we’re getting both of these notes saved to local storage when we create them or update them, and loaded from local storag. When the app is refreshed, let’s just make a change to one of these to make sure that the saving is working properly.

Okay. Refresh. It looks like we’re good. Awesome. Our app now persists data into local storage. Thanks for working along with me on this one. I tend to skew a lot of my content more towards the soft skills that you need to become a web developer, but I’d also like to produce some more of these too, if this is something that people find interesting.

Thanks for watching and I’ll talk to you in the next one.