Web Storage APIs Replacing Web Storage with IndexedDB
Transcript from the "Replacing Web Storage with IndexedDB" Lesson
>> With everything that we've covered so far, we are ready to replace now our local storage implementation with IndexedDB. What do you think? So follow along with the instructions here. We are in databases, setting up IndexedDB. So the first thing that we should do is to add the wrapper, okay?
[00:00:24] The wrapper here have the link to actually get into the repo. By the way, the wrapper was created by Jake Archibald that you may know from the Chrome team. Well, installation, there are three ways where you can install or use this library. Like with npm, in case you are using modules like our case, we could use this way like you import from directly a CDN these global functions.
[00:00:58] In this case, this is going to replace not actually replace, but it's going to be on top of the regional API okay but only for that module. So add on every module that you need to use i index DV you have to import that. But I think that for our case it's better to use like the old classic import that will actually be a global thing for your whole project.
[00:01:22] Okay. It is just copy and pasting the script that you have here in our html. Okay. And I'm going to paste that actually in this case I think the order will not matter a lot. So I'm going to index html. I'm going to paste the script before the app, just that.
[00:01:45] So just with that, we are ready now to open databases and using IndexedDB with this library, okay, with this wrapper. Again, this wrapper is not actually changing IndexedDB with a different API. It's just adding promises. And helping us with this single transaction operations that's all. All the rest is actually the IndexedDB API with the same arguments with the same way of working that.
[00:02:13] Same way we're thinking. That's why it's a very simple API. Okay, makes sense. Well, so what do we need to change now? Well, we need to change. Again, order js, load and save. Okay, if you wanna keep those, you can like we can call this load in webstorage saving webstorage in case you want to keep those versions.
[00:02:37] And I'm going to create to other versions that that will be, IndexedDB based. Okay, make sense? First both when we are loading the database and saving the database, I should open the database. So maybe it's a good idea to create also an open database function that we are going to call from both load and save.
[00:03:07] Makes sense because I know that I will need to open this in both situations. And the other thing that I need to do is to convert these three functions into async functions. Why? Because I know for sure that I'm going to use a weight because the library that I'm using the wrapper is using promises.
[00:03:30] Okay? Make sense? So we need to open the database. So this was actually idb, that's the library OpenDB, a name, we can prefix this with coffee masters, so for example, coffee master web storage or storage or whatever, the version number, and then I'm going to provide an object that will contain a function with the name upgrade.
[00:04:01] Okay, like so. Now, we did the upgrade. This is a place where we can create data stores. In fact, it's the only place where we can create data stores. So it's that database is open in a way where we have permissions to actually change the schema of the database such as creating new data stores.
[00:04:26] Does that make sense? And this function receives some arguments such as the new version, the old version, and so on. But the first one is the database reference. And I need that because now I want to talk to my database. And I'm going to create an objectStore with a name, okay?
[00:04:49] Which name? Any name. This is the order section, so we can call it order. This is asynchronous API so if I want I can wait for it and that means I need to convert my function into a sync. Make sense? So this will open the database and create the database the first time.
[00:05:13] That's kind of the idea. If it's already there, so if I already have these name with the version number one, he will just open it he wants to execute my upgrade function. Does it make sense? Yeah any question? The only thing that I should do is this is a function that I will call from load and save.
[00:05:39] So I need to by the way, this is not idb Carson, it's idb lower case. I need to return this and also I need to wait for it. Okay, so every call or most of the calls that we have now in IndexedDB, I'm returning a promise. Okay, makes sense?
[00:06:08] Any question? Nope? So let's do the same first. That was the simplest one remember before we so what I need first is is a reference to the database. So now I'm going to wait for order openDB. That's actually the method I have just created. That return will return me a reference to the database.
[00:06:35] And here I can, directly go, and save an object, with the API, okay? It's actually, pretty simple. So, I can add, or I can put. What's the difference? Add will add a new value, always a new value. If it's already there, it will give me an error. Put, will put a value over the key.
[00:07:04] If it's there, it's going to replace that. If it's not there, it will just add it. So put it both insert and update in this case. So it will just make sure that we won't have more than one for that key. Okay. Make sense? Just remember that we should always await for everything here.
[00:07:28] So it's a wait for a put. So these methods always work in the same way with the first argument is actually the name of the objectStore, right? So order. Then, be careful because BSCode is showing me the help of something completely different, okay? So it's a cache API, but that's not the API I'm using right now.
[00:08:19] That's how it works, idb, so be careful. Because on local storage it was key value and now it's value key. So first we are going to, I'm keeping this simple for now, so just doing the same as we was doing before. So I'm still stringifying the cart with the key cart.
[00:08:41] I don't need to prefix the key as before because I already have the database prefixed make sense? So you just need to prefix whatever goes first in the browser as a reference to the storage, Okay, make sense? Do you need to do anything else choose for saving? Nope, that's all.
[00:09:06] Let's see. This in action. So if I refresh well now because it's loading is empty, it's not loading, which is okay. I will add this to my cart I cappuccinos as well. So now, let's refresh. I'm still not getting nothing because the load is empty, but look at the quota.
[00:09:29] Now, I'm using some quota. It was zero before. What is that? IndexedDB and it's currently using 3K, okay? Which is bad. That's fine. Expectable. So if I'm going to application, now within the storage, I can now see IndexedDB has a little arrow there. That means that there is something inside.
[00:09:53] I can open that. I have the database cm storage. I can see here the current version. How many objects store do we have here? I can delete the database from here from dev tools, and I can open that database and I'm seeing my data store. And in the data store I have my cart.
[00:10:14] That is not working because I still have the loading problem. Okay, so but look at this if I'm adding something to the cart I need to refresh here the cart is there. Again here I'm just taking whatever I have in web storage, and moving that into Indexed DB.
[00:10:33] Maybe you're thinking, well, that's an array. Maybe we should store element by element, okay, but for this exercise. But when I'm making this simple, it's just taking the same that we have in web storage and replace that with an IndexedBD version. Any questions so far on this? Makes sense?
[00:10:55] Does it look scary? The API?
>> I have a question.
>> Is there any kind of best practice or rule of thumb to since in our case, the object only contains, like, nested primitives and serializable data. Is there any reason to prefer to stringify the object in our code versus storing the object in a verbatim?
>> In this case, no, there is no reason, just to keep the same as the Web Storage. But you're right. Can we just store the cart? Yes, because it's something that we can clone. If it's something that you can clone, you can story safety. So yeah, you're right.
[00:11:38] We can remove the JSON Stringify at all.
>> Is there any kind of best practice or thing to keep in mind?
>> I mean if you don't need the Stringify, you don't need that, it will be more performant to not to have it. Yeah, it's up to you.
[00:11:52] So now, it's time to talk about the load. Where on the load I will also need In the same database, so I will wait for openDB. So now that I do have this, so what do I need to do first? So remember in our code with webstorage I was checking if I do have something, okay.
[00:12:14] How can we ask something like that? Here if I do have something with the API that we saw that we cover in the slides I could check count. Remember there was a count. So I could check that, that's one option. If not try to just have to take the cart, okay.
[00:12:41] How? Await db.get. We do have a key, so it's first, always first goes the store name. So from order that's the store name that we were using here. So from the same thing, I want the key cart. Make sense? And I can also check if it does exist.
[00:13:09] If it's not, it will give you something that will trigger a false. So that means that, I mean, I can count or I can just get the value and if it's not there, it will not work. So it will be false in this condition. So now I'm here, I can try to again we can try to remove the JSON stringify and JSON as he suggested and it should work.
[00:13:36] In this case because I wanted to keep the same experience just to show you how you can just move quickly from local storage to something different. But again, we have the same problem that someone can get into my IndexedDB and make this JSON invalid. So I should always, every time you're working with client side data storage, you should always think that everything will fail.
[00:14:04] Okay, so now you can say data corrupted or whatever. And if it's corrupted, what you can do, you could delete the database or you can delete the data store, okay? Something like that. The other thing that I need is to call render. Because if I don't rerender I'm still seeing an empty cart.
[00:14:31] So I will add an Americano I had three Americanos, I will refresh. I still have three Americanos. But now, I'm not using web storage, I'm using IndexedDB. Again in this example that is pretty simple, we will notice a difference. But if it's a more complex scenario, this version is much more performance.
[00:14:54] We have any question this first simple idb example.
>> Opinion question. I think the two I've worked with or encountered before were idb and Dexie. Did you choose idb for this for purely pedagogical reasons? Is there, you know?
>> So the question is around why am I choosing to keep an idb wrapper and not Dexie or any other thing.
[00:15:23] In this case it's a matter of choice. So when you go with Dexie, let's see vaccine. So we know where we're talking about. It's a DB wrapper, but don't just a wrapper is changing the way you're thinking okay? So yeah, I like the Dexie, so I like it [LAUGH] But it's not actually following IndexedDB practices.
[00:15:46] So I think that for a workshop, it's better to cover the library IndexedDB. Maybe it's too much to cover the original API because no one likes that API. So that's why today you will see more websites using things like idb than other frameworks. Because the other frameworks like Dexie it's a matter of taste at one point, right?
[00:16:13] So, for example, this is how Dexie looks like you'll create an idb database you create a new Dexie and it has the same because it's using the IndexedDB behind the scenes. It has the same ideas like you have a version you create here at the store with these you are creating the primary key, and additional indexes that we haven't seen yet.
[00:16:33] So it has it like a different syntax, yeah, maybe you can say, well, I think it's a better syntax, yeah well, maybe. And you can create some kind of, sort of SQL but it looks like Link or LinkU for.NET. I'm not sure if you have seen that. Where you kind of create queries with functions, with some kind of functional programming.
[00:17:02] And internally it's using the IndexedDB APIs. Okay, but it's just that it's a matter of taste. If you like Dexie, go ahead. It's a good library. It's well supported in the community, so yeah, it's fair to use it. But well, this is 25k against one, yeah. I think that it depends on the project if you feel like, yeah, I have enough data, I have enough data store, enough complexity that will worth to use a better library.