NuxtJS + VueX: Deserialization, load strategies, middleware (Assembling a serious Nuxt app, part 3)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
all right tell me if you've seen this problem before so you've got your app and next and it's great it works it does everything it's supposed to but you see that every time that you go to a new page it's loading new data even if it's data that you already have and also when you're using async data there is just a lot of code here and a lot of it seems to be repeating it's not the exact same but there's a lot of similarities that you feel like should get cleaned up well that's what this video is here to help with but first let me get this out of the way this video is not for everyone you need to have a basic knucks knowledge and a basic view X knowledge or you need to have watched the previous two videos in this series which will give you enough knowledge to understand what we're doing today and those previous two videos I'll link to in the description all right so this is what we're going to be doing today in order so first we're going to be moving from async data to view X and we're gonna be doing this in a pretty naive way basically copying it over and changing enough stuff to make it work then we're going to refactor that code so it's less repetitive and easier to read using deserialize errs destructuring and some custom methods then we're going to have a strategy discussion on how we load data and the different types strategies available to us and which ones work best for our particular situation and then once we've chosen that strategy we're going to implement that strategy using pre-loading middleware and the RSVP library so we've got this acing data call and two others like it and they're all fairly complex and we're likely to add more and more as time goes on so how can we simplify this well we'll be coming up with some more sophisticated answers to that later but for now we're going to port all of it over to the view X store so what's that going to look like so first we're going to replace a Singh data with fetch and we at the store through their context and we will call store and actually we'll call a wait for the store so our template waits until it's all loaded and I'll call store dispatch and we'll call this action load all videos now we need to take all this stuff that was happening in a Singh data and make it happen within load all videos so we'll start with just treating the actions hash and creating a load all videos method within it all right so we will take all of this copy it and paste it in here now there are some changes that we're going to need to make to make this work so first the has to be a sync and then Axios here we used to have access to it from here and we could I guess pass it in but from within the store you can just call this dollar sign Axios and you'll have access all right now all of this should still work the same it's down here that we need to change so we're not just returning this data now we're putting into the store so instead of a return we'll need to do some commits so we'll get our commit function from the arguments and then we'll make two commits one is set videos and we already have that mutation so we'll just take this value that was being returned his videos and set videos with it our next which we'll be making in a second is set tags and we'll be returning the tags just like they were returned here before all right so we have committed all the videos and the tags at least we have committed those mutations we need to actually make the set tags mutation and we can go ahead and get rid of the current video stuff all right so we create the set tags mutation and it's pretty simple and then we'll go ahead and have the default state of tags be an empty array all right so what we've done so far we have our fetch hook which will dispatch to load all videos which will go grab our videos and the tags associated with them and instead of returning the videos and tags we will commit the mutations to set them in the store so we're still not going to be able to access those well we're able to but we're not currently accessing those in here but let's go ahead and make sure that they are in the state so you can see there's an error here but the base state has these tags in these videos loaded from the server-side rendering and so that means that this is working correctly now let's just go ahead and get our template access to those tags and videos and that is actually really easy so it will use map state all right and now everything is looting nicely all right so we've taken care of our first instance of acing data and turned it into this let's go ahead and see if we can make our second instance look just as good so we'll go over to our watch page and so we'll go through many of the same steps so have our store and here we have some params and yeah we'll go ahead and use a wait and then call store dot dispatch and now we'll just load one video and send in the video ID pram then we'll take the rest of this code and stick it in to load one video in our actions hash and that actions hash will of course be taking a commit as well as a video ID all right so how can we adjust this code to make it work so we'll replace this params dydy with a video ID so that works now and then instead of accessing a dollar sign Axios directly you will have it on this dot and then instead of returning the values we'll need to commit them so the tags is easy we already have set tags and then we can just send that in now what do we do with this singular video we could bring back current user but I actually don't like that pattern it was kind of a mistake to use it in the first place there are exceptions of course current user is great to use and current video might even work if for example there was a video that was playing that was following you across routes then current video would make sense but for our case uh let's just go ahead and put that video in the videos array so we'll set videos and just do this and I know what you're thinking won't this overwrite the videos that we set here and the answer is yes just like the tags will overwrite so the tags we have here will overwrite the tags we put in here but currently all the data is being basically reloaded on every page so there's no downside to that currently in a future section I'll go over different loading strategies and how they interact and when to use each one but for now this works all right so we go here we have dispatched to the store in our fetch hook and now we'll need to use our computed properties so we will import and we'll have map state from view X and this is old map state from when our stuff was big enough to have modules we'll be getting there but not in this video so we'll be mapping the tags and the videos and we'll also need to use the correct syntax instead of the incorrect syntax much better so we've got our tags and we have plural videos but now we need to find our one video we could sheet and be ok it's the only video in there just grab the first one but I want to do something that is a little bit more robust so it will be able to stick around even as we change our store alright so we grab our videos and then we find and the video ID will match this dot dollar sign route dot params dot ID and then we will return this now let's test it out by going to one of the watch pages all right there we go it's working now let's tackle our final instance of async data so once again we will await and dispatch to this store and in this case let's call it huh so we're loading a tag and then all the videos on that tag and all the tags on those videos so call it load tag and relationships and then we'll send in the ID of the tag all right and then the rest of this will go in our store we will once again make the necessary changes and then instead of returning stuff will do commits and let's just copy this here since we're doing basically the same thing at the end and we call this something slightly different but they're pretty much the same thing and then the main tag instead of setting that separately we're just going to find that out of all the other tags that we've set so we don't even need to do the processing on it right here so then we'll go back to here we will import map state from view X we will have our computed hash which brings in the map state with the tags and the videos you're sensing a pattern here right and then we will find our individual tag from out of all those tags so we'll grab the tags and find it based on the route params dot ID and double equals not setting it all right and if we just change videos on tag to videos then this should work should if we return that value all right and now we have taken all of our acing data stuff and put it into the store I gotta admit so far it's been a decent amount of work and not a huge improvement but it does put all our stuff in one place and that has several advantages so for the Knicks section it'll mean we'll be able to look and see where the similarities are and start abstracting them and later on when we start changing how stuff is loaded then we can for the most part just leave these be alright we're finding the video out of the videos and it doesn't matter how the videos are loaded as long as the correct video is loaded now is where stuff starts to get fun we have all three of these actions lined up one in front of the other and we can start to see where some of the code repeats so we can refactor it and abstract it away technically we could have had utility helpers that did this back when it was async data but it's a lot easier this way we'll grab the low-hanging fruit first so we have a lot of places where we loop through our tags to add an ID onto them as a matter of fact we do that in all of these the reason we do this it's because the form of the data within our app and the form of the data coming over the wire is different and the name for changing the data coming over the wire to match what you expect it to be is called deserializing so let's go ahead and create a method called deserialize tags which takes an array of tags and just changes them so that they're in the format that were expecting so this line will replace this line so let's go ahead and create that function it'll take some tags and then older sloop through them and set the ID on the attributes and so you can see this is easier to read and we can go ahead and throughout all these we'll be replacing three lines with a one line there's an additional benefit which we'll see in the next section is if we want to add something to the deserialization protocol then we only have to add it in one place instead of adding it everywhere that we are deserializing tags alright and so now we can do this for the videos as well so this is our D serialization for the videos so we will replace it with deserialized videos and copy what it's actually doing and create our method down here and then we can go ahead and use this here and here we're only doing it to one video but we can still use the deserialized videos function we'll just create an array out of that one video just like we do it when we're setting videos with the mutation alright so we've made some gains in abstraction because we're not repeating ourselves and clarity it does exactly what it says instead of having to interpret the loop and stuff is a little bit more future-proof so if we want to change something we only have to change it in one place but there's more we can do so we have these two lines here which are very similar and I bet we can abstract some of that away so we will have something let's call it get data where all we do is send in this and wow that is not the autocomplete I wanted alright and now instead of getting something called response what if it could give us videos and tags directly that would be pretty cool right then we could delete these two lines in this line and we're not losing anything of substance we're just basically losing boilerplate well we can't do anything quite this good but we can get close and so let's start with something easy so let's get data and included from our get data method and so that means we'll bring this line back but it's simpler and we'll bring this line back but it's simpler and these will be gone very soon but one step at a time alright so let's create our get data function it will take in a URL and then it's going to return data and included in between it's going to use this dot Axio stock and get to call the URL and that will of course be a wait and so we have to make this an async function alright so we'll be getting our response here and this is where we're going to be getting rid of our boilerplate because instead of having to response data data everywhere we just do it once here let's test this out and make sure everything still works oh it looks like we cannot read property Axios of undefined so this is undefined that's because it's no longer within the actions hash knucks does something special with the actions hash so it does have access to this but we do not have access to it down here but what we can do is pass in ax u s-- and we actually don't need the dollar sign anymore all right so that means whenever we are calling get data we'll need to pass in this dot dollar sign Axios has the second argument and now it should work perfect but can we do even better and the answer is yes so we're currently destructuring to data and included but we can D structure like this meaning that you can just get rid of those lines and now our load all videos is pretty nice and it's still working let's make this work for the load 1 video action so we'll replace all this with get data and we all pass in Axios and then we will make it so we're assigning video and tags and then we can delete these lines we'll test it out by going to an individual watch page and it works finally we'll do it for load tag and relationship and in this case we're only working with the included data but it's still useful so we'll change us to get data and here we'll grab the included array and we can't do anything more with it here because we are filtering to get the videos and the tags separately but still this is a nice little improvement to the length of these lines and this is a huge improvement to readability in general so here we are grabbing the data we are deserializing it and then committing it so pretty clear what we're doing the similarities between all of these functions became really obvious once we put them one after another so I could go and look at them at the same time but if we decided to take these back to using async data we could still keep a lot of the gains we've made we could import the deserialize videos deserialize tags and get data methods from a utilities folder and we could import them into each of our individual components and use them there but that's not the direction we're going in this series and what direction are we going that's a good question we're going to discuss our strategy next now thanks to our work in the last section we have much nicer code very easy to read but we're still using the old strategy of completely dumping the old data and replacing it on every page load is that the correct data loading strategy for this app for the purposes of today's discussion let's break up our data loading strategies into three main categories the first which we've been using is load and dump so you load it up when you're getting the page and then you dump it when you're ready to go to the next page and so this is what our current app uses it's what you're going to use if you're using async data in general and it's what server-side rendered apps use the next is pre loading so that is at the beginning you just grab all the data you think you're going to need and then you have it all client-side and just use it as you need it and the final one is caching which is basically you need some data you check see whether you have it if you do then you just use that data if you don't then you call out to the server or if you want to do half caching help you but not completely rely on it you know just in case stuff updates quickly you can check and if it's there you optimistically show that data while still calling out to the server and when the new data comes in you replace the old data with it so that will get people the results sooner but it will also get them updates which one of these is the best well from a pure user experience standpoint and the best would probably be a well-designed caching system the key word here being well designed a caching system can be difficult and it uh I mean if you design it poorly then you'll get weird everywhere and no one wants that so if you have the time to put into a caching system and you think your app is going to need it then go ahead and do that but these first two are a lot easier and we can do a combination doing caching when needed doing a pre loading when needed and doing the load and dump strategy when needed as well the correct combination for you depends on how your data looks so for example if you are running a social network then pre-loading would be out of the question because it'll just be too much data hundreds thousands possibly hundreds of thousands or millions of new posts every day you know you'd be loading them and by the time you finish loading there'd be more so yeah not good on the other hand let's say that you're a photographer and you have a portfolio site now obviously we shouldn't preload all of the images but I think pre loading all the URLs for the images is a great idea because you go to the next photo you hit next alright and you don't want to have to call out your server grab just one record for that photo say okay here's the URL then you go to AWS and get the photo no you have what a hundred photos you just get all of the URLs in an array it's easy and pre load all of that with your site our particular example today with the data we have right now it leans more towards the pre loading side so we're gonna have like I'll make maybe one video a day tops and then each that those are gonna have like three tags out of it to pool of maybe a hundred tags and so we can preload all of the URLs and metadata for that really easily on the other hand if we start a commenting section then for those comments you never know how many comments that could be there could be a hundred per video and then for those we would want to use a load and dump strategy so we can mix these strategies based on the data type and the data usage and for most apps you will want to do pre loading for your current user even if everything else is load and dump or caching all right we are finished with the philosophy and we've decided to take all of these and combine them so we'll just be loading all the videos and all of the tags at the beginning of the first page load so you'll go to your page and it'll load and when you click this nothing new will load we'll just be using the data that's already there pretty cool but how do we do that we're gonna take it step by step the first step is going to be a huge leap forward in terms of the simplicity of our code but a little bit of a step back in terms of how much data we're pulling from the server but then we're going to improve that all right so we're going to keep our load all videos action and we're going to add a load all tags action and you may be thinking wait why do we need that in modal videos we're setting the tags but these are only the tags that are associated with videos and for our current setup user facing this is fine but when we get to the admin we'll want to be able to access tags that don't currently have videos attached so for the sake of the future we are doing two separate little video and little tag actions alright so that means we can simplify load all videos a little bit since we no longer have to deserialize the tags or set tags those both go and load all tags and then we'll go ahead and create the data call in tags that's pretty easy and now it's just these two methods and we can completely delete these other two methods all right our actions are pretty easy right there now we'll just go ahead and adjust all of our components so they're calling load all videos and load all tags and this page is working great that's pretty easy it was already loading all the videos and all the associated tags for the video watch page let's go ahead and see if that works yep it sure does then we'll go to the tags page and paste in our to store methods are to dispatches to the store and we'll go to a tag and it looks like every tag page is showing every video so what we're going to need to do is here instead of grabbing all the videos we're going to need to filter them out based on the video IDs that are on the tag so we'll call this videos on tag you know like the computed property that we used to have all right--so videos on tag and we'll get our tag for this page and with the video IDs here but wait we have not yet put video IDs on that tag so the list of videos is going to be in the relationships dot videos key not in a video IDs tag by default and so during the deserialization process we're going to have to change how that data is shaped and fortunately we know exactly where to put that stuff now so it's in our deserialized tags so we'll attributes dot video tags equals T dot relationships videos dot data dot map all right so we are now setting the video tags on each tag wait video IDs we should name it correctly all right so we've got the video IDs now how can we use this list of ID's well we could get our list of videos and we can filter based on whether that video is in the list of IDs so return this dot tag that video ideas dot includes this videos ID and because of the format we'll actually have to call to string to make this work all right and now we'll see that it is working it's filtering the videos based on whether they are included with the tag and I would say that this is in general better design than what we had before because before if you know someone added a video that wasn't related to the tag into the video state up here then it would just show up here uh-huh we did not have the control in the correct place so we've got this all working we have our fetch in three different places and we're calling the same two actions on each of them this is simplified our lives quite a bit but it hasn't made it any better for the user because we are calling this the server twice every time they change a page so let's go ahead and fix that here in fetch we have the context object and we can bring something called from from the context object and this is basically what is the most recent route the route you're coming from and I can put in debugger so I can just show you it looks like this and odd you're coming from a different tag before but if this is your initial page load there will not be a from object so you can define is initial page load equal to not from and I know this is longer than this but it's more clear for what we're about to do so if is the initial page load then we do these dispatches you and if it's not then we don't and you can reload and we'll see that okay we've loaded the page we'll click on a couple more tags and we'll see that we have not made any other API calls we are working completely from the preloaded data and so we can go ahead and copy and paste this into the two other times that we're fetching this data and so if we do this then we'll be able to go throughout our entire app and not reload anything a single time so let's demonstrate that reload we'll get the data and we'll go to all different types of pages and there's been no extra API calls so this is great as far as it goes but this is huh seven lines that we're gonna have to paste into any route that we might have the user loading so how can we get around this the best thing to do would probably be to go in put this on something that was above all of these pages so currently we have it here we have it here and we have it here and in the pages directory there's nothing above it but there are layouts so will this work will we be able to create a script tag here and put in a fetch method a fetch hook and the answer is no there is no fetch hook on the layout but there is middleware and so we can make this work so here's what we would do we would say all right we're gonna call this middleware and the name of the middleware will be load videos and tags and now we have to go to the middleware folder and create a load videos and tags dot j/s file and then we will export default a function and this function the first argument is a context object and from the context we can get nice stuff like store and from very useful for what we're going to do we can also make our middleware async and what are we going to put in that middleware ah this we all paste these five lines in and I don't think we'll have to change them at all and that means we can get rid of this fetch we can get rid of this fetch and we can get rid of the other fetch which is hiding around here somewhere here we go and when we load our page it's still all working so we can see that we can go to any of these pages both as a first load and as a second load and if we go to our inspector we'll see that we are still not loading any extra API calls after the initial one but wait we can make this even better so currently we have to wait for load all video to finish and then we start load all tags and then we can do everything else but there's no reason for load all tags to wait for load all videos so I'm going to bring in a promise library called RSVP we use yarn ad to put it into our project and then we can import RSVP from RSVP and I don't know if there is a standard view promise library this is the one I'm used to using but if there's a standard one let me know when I can switch to that alright so we can use the all functionality which basically says so we put the await in front of it so it forms a new promise that will return when both of these promises are resolved or I shouldn't say return it it will resolve when both of these promises are resolved and you can add in as many as you want and it has cool stuff like hash as well if these have return values that you need named so there we go we are done with this section we can now access all of our videos and all of our tags from any of our pages and we are not going to be calling out to the server every time the page changes and all we had to do was create this middleware put it into our layout and define these two pretty simple actions we have made a lot of progress remember when our code used to look like this and when every time we changed pages it would call the API well both of those are fixed now awesome let's do a quick review of what we did first we took the async data that was in our components and we moved it all to the store index without changing too much except to enough to get it to work and then instead of calling async data we use the fetch hook and dispatch to the store and then we got our data from the store state using map state in a computed property and we went ahead and did that for all three pages and sometimes we would calculate out a specific tag or video from the plural in the state so this cleaned up our components quite a bit but it transferred all the complexity to our data store where it's just three messy functions all in a row and at the end of each one instead of returning the data we commit it to the store with a mutation so that took a while but it was fairly simple then we refactored our store so all this stuff that was just looping through stuff changing it that got put in to deserialize methods so dear serialized videos and deserialize tags fairly simple but they cleaned up our actions considerably and we also made the get data function which abstracted away some of the Axio stuff only a tiny bit with the Axios it was more with abstracting away the json api boilerplate and the last cool thing from this section was this little trick so you may have used destructuring before used it like this in the basic form but you can give an alternate name to it like this so we were able to assign stuff to video and tags which had previously taken three lines and now we get it all done in one then we discuss strategy for a while and eventually decided to preload all of our data on the initial load and so we wouldn't have to reload anything when switching pages and so our primary tactic for that was first we can solid dated everything into a load all videos action and a load all tags action and then we created a middleware that calls both of those and both of those promises go to make a new mega promise with RSVP doll and this will only run if there is no previous page so if it is the first page that we're loading and then we go to the layouts our default layout and tell it to load that middleware and now we are done for today I know that was a lot of information but I learned a lot and I hope you did too and I'm excited for what we're gonna do next time which is basically take the rest of our app the admin section of it and put it into our next app with the exception of authentication authorization and all that which will be in the video after that I will see you then you
Info
Channel: Vue Screencasts
Views: 18,329
Rating: 4.9504642 out of 5
Keywords: Javascript, vuejs, vue, javascript frameworks, web development, frontend javascript, nuxt, nuxtjs, vuex, deserialization, middleware, nuxt middleware, loading patterns, loading strategies
Id: sSbahlvDfS4
Channel Id: undefined
Length: 47min 19sec (2839 seconds)
Published: Sun Oct 20 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.