Why Lazy Load Data0:00
All right, next up we'll learn how to lazy load data by leveraging the Intersection Observer API, even if you don't even know what that is. I'll show you how. So here we once again have my courses example. If I click on it, we have a list of fictional courses, and then at the bottom we have all of our dummy topics. Now before we get started, just as a refresher, remember if I open up the Network tab and I open Courses, we will fetch all of the data that's required for this page. So that would include the courses as well as, at the bottom, the list of topics. And that's potentially okay, but it's also a shame that we have to fetch this data if
So that would include the courses as well as, at the bottom, the list of topics. And that's potentially okay, but it's also a shame that we have to fetch this data if we may never even require it. Now in this example, it loads incredibly fast and it just doesn't matter. But in some situations, it can take a little bit of time. So in the last episode, we learned how to defer data, Inertia, defer, just like that. So now on the first page load, we will fetch the courses, but then a second AJAX request will be made to fetch the topics, and then that data will be merged into the page. So if we give that a shot, and again, this is all a refresher from the deferred props episode.
So if we give that a shot, and again, this is all a refresher from the deferred props episode. So if I click on it, now we have two requests, one to fetch all of the courses, and then one to fetch only the topics. Okay, so this is better. We are now deferring the fetching of these props, but we're still in a situation where the user may never even get to this point, you know what I mean? Maybe at the top, they just find the Course they want and they click on it, in which case we loaded and rendered all of those topics for no reason at all. It was a complete waste of time and energy.
Mark Props as Optional1:46
we loaded and rendered all of those topics for no reason at all. It was a complete waste of time and energy. So it would be cool if we could lazy load the topic data so that we fetch it only if the user actually cares about it or needs to see it. And I'll show you how to do that now. Let's switch back, and we're going to change this to inertia optional. So what this means is when the page loads and we fetch all of the data, it'll grab the courses, but then for topics, it'll say, ah, no, this is optional. I'm not going to include it with the initial request. Come back, open up the network tab, I fetch it, and now you'll see that, yes, we grabbed
I'm not going to include it with the initial request. Come back, open up the network tab, I fetch it, and now you'll see that, yes, we grabbed the courses as you see there, but if I scroll to the bottom, no, we didn't fetch the topics because we explicitly labeled it as optional. So of course, now if I scroll to the bottom, here's the topic section, but we didn't request it, so we don't see it. So traditionally or manually, here's what we might do in these situations. Let's go into my view component, and at the top, why don't we do something like this? We'll say, well, when the page mounts, I want to manually fetch that data. So I could say, all right, pull in the router, and we'll do that right up here, and I'll
We'll say, well, when the page mounts, I want to manually fetch that data. So I could say, all right, pull in the router, and we'll do that right up here, and I'll say router.reload, but I'm going to be specific about what I want. I only care about the topics in this case. Okay. So now, that'll do the trick. So if we come back, once again, I just want to show you this. We fetch it, and now, yes, we have the initial request, and then we've manually made a second request to grab the topics, and if I scroll to the bottom, now we've got that. So yeah, you can imagine if you only want to fetch the topics after some kind of logic.
request to grab the topics, and if I scroll to the bottom, now we've got that. So yeah, you can imagine if you only want to fetch the topics after some kind of logic is done, even if in this case it's like a set timeout, let's say after 3 seconds, then we will fetch the topics. Well, of course, that will now work. One, two, three, and we'll see that second request come in. Okay. But, you know, that doesn't really solve our problem, does it? I really want to say, well, if the user keeps scrolling and scrolling until they get to the topics section right at that point, I want to make the request.
Manual IntersectionObserver Setup3:55
I really want to say, well, if the User keeps scrolling and scrolling until they get to the topics section right at that point, I want to make the request. So again, manually, we could use the IntersectionObserver API, and that might look something like this. First, I'll get rid of these, and I'll comment this temporarily. So once again, we will listen for this page component to mount, and then we will instantiate our IntersectionObserver API, and AI is trying to do the work for me. Not yet, AI. Yeah, so we are going to instantiate this observer, and we'll say, yeah, I'll take it. So we're going to loop over the entries, and for each one, we'll say, well, if it's intersecting,
Yeah, so we are going to instantiate this observer, and we'll say, yeah, I'll take it. So we're going to loop over the entries, and for each one, we'll say, well, if it's intersecting, which means have we intersected the thing to which we are observing? If that's the case, then, yeah, pretty good, AI. That's basically what we want to do. If we're intersecting that section, then we should reload with the topics, but let's get rid of some of the root margin. I'll keep it like this, and then we will call observe. Yeah. So if you want, a long form might be to call this observer, like this.
Yeah. So if you want, a long form might be to call this observer, like this. This might be how you see it in the wild, and then you would say observer.observe, and then you would pass in the thing to which you are observing. All right. I think this is right. So to make it crystal clear, we will say alert intersecting, and we'll give it a shot. All right. So at the very top of the page, I'm going to load or refresh, and if I scroll down, right at the point that we reach the topic section, we don't see anything at all.
So at the very top of the page, I'm going to load or refresh, and if I scroll down, right at the point that we reach the topic section, we don't see anything at all. AI, you know what? I trusted you, AI, and you screwed me. Failed to execute observe on IntersectionObserver API. Aha. So let's see what the issue is. If I scroll back, ah, yeah, here it is. So if I scroll down, I don't have an id here. So let's give this an id of topicSection, and then we will fetch that.
So if I scroll down, I don't have an id here. So let's give this an id of topicSection, and then we will fetch that. All right. So does that make sense? We are observing this DOM section, and we're saying, well, at the point we intersect, do an alert, and then make a request only at that point to fetch the topics. They get merged into the props, and then it gets re-rendered by Vue. Okay. So let's try it one more time. We scroll down, and at the point we reach the topicSection, there we go, ta-da.
So let's try it one more time. We scroll down, and at the point we reach the topic section, there we go, ta-da. We get our alerts, and we see our topics. Okay. So this would be sort of the manual way that we could lazy load this data. Just to prove it to you, if I click on it, here's our first request where we only fetch the courses, because we need those immediately, and nothing else. But if we da-da-da-da-da-da-da-da-da, if we scroll down to the topics, there we go. We get our alert, and then you see the second request. So that's literally lazy loading the data.
Using WhenVisible Component6:40
We get our alert, and then you see the second request. So that's literally lazy loading the data. But as you can imagine, this is probably something you would do a lot. So for that reason, in Inertia 2, we can streamline this, and I'll show you how. I'm going to get rid of all of this junk. We don't need this. Get this out of here. Get rid of that, and get rid of the router. All right. Let's scroll down.
All right. Let's scroll down. And yeah, in our topics section, I'm now going to wrap this within a handy-dandy WhenVisible component. And you know what's cool? You don't even have to wonder what this does. You already know. Well, this code should only render when it's visible. Okay. But now, do I need to lazy load some data as part of that?
Okay. But now, do I need to lazy load some data as part of that? Yes, of course. So I will specify the data here, and I want to reference my prop name, in this case, topics. Now, if there was other data that needs to be lazy loaded, then of course you could provide an array. So I could do topics, and then anything else I need to wait for. Both are fine. All right. And believe it or not, that's all we have to do.
All right. And believe it or not, that's all we have to do. When this section is visible, we will lazy load the topics. And just to be crystal clear, make sure that we declare this as optional. And in fact, I'm just going to show you this right now without it. So if I kept it like this, and we gave it another shot, how many times am I going to open the network tab in this video? We open it, and yeah, we're not really getting much bang for our buck, because we load the courses, and then if I keep scrolling to the end, where are you? Where are you?
courses, and then if I keep scrolling to the end, where are you? Where are you? There we go. We load the topics. So we're not really lazy loading, excuse me, we're not really lazy loading anything. So that's why I explicitly wrapped this in Inertia optional. I don't want to fetch this one right away. It's optional. Instead, I will use the whenVisible component to lazy load and fetch that data. All right.
Instead, I will use the whenVisible component to lazy load and fetch that data. All right. One more time. Open up the network tab. Open up the courses. All we do at the beginning is fetch the courses. But then as I scroll, once we reach the topics section, we're going to see another request, and there it is. And it loads in. It's pretty cool.
Configure Buffer and Fallback8:48
And it loads in. It's pretty cool. All right. So configuration. A couple of things we could do. Let's go back into our courses page, and if you want, you can add a buffer. And this will be a pixel value of how much before you reach this section should we load the data in. So, for example, imagine loading that data takes a few seconds. Well, if I were to switch back to my routes file and we simulate this, let's turn this
So, for example, imagine loading that data takes a few seconds. Well, if I were to switch back to my routes file and we simulate this, let's turn this into a traditional closure and then sleep for three seconds or something like that. Well, as you can imagine, if I switch back and refresh, yes, we will lazy load the data, but it's going to take a few seconds, right? And I don't see any feedback there. There we go. Now, after three seconds, we fetch that data. All right. So, one, we need to provide feedback to the user, and two, if you want, you could specify
All right. So, one, we need to provide feedback to the user, and two, if you want, you could specify a buffer. So, let's go back in here, and yeah, I could say, well, I don't know, maybe 600 pixels before we get to the beginning of the topic section. Let's go ahead and trigger that. All right. Let's give it a shot. Refresh. Open up the network tab, and let's start scrolling.
Refresh. Open up the network tab, and let's start scrolling. And it's going to be a little hard to see in the demo, but rest assured, when we're about 600 pixels above the topic section, where are you? Come on. Come on. There we go. Notice we've already made that new request even before we've reached there, and that's because we specified a buffer. So, yeah, that might be useful to give yourself a little bit more time, but another option,
because we specified a buffer. So, yeah, that might be useful to give yourself a little bit more time, but another option, of course, is to provide some feedback to the user. So, I'm going to get rid of this, and I'll say templateFallback. So, this is just like when we were learning about deferred props. While the data is loading in, what do we want to display? So, maybe I'll just steal this section here, and actually, you know what? What should we do? Let's put this all. Yeah.
Let's put this all. Yeah. Let's put this all within the topic section, like so. Yeah. Okay. Sorry. A little messy, but it should all be contained here. Okay. So, now we don't need a grid, and we can just say loading, and then I will reference my loading spinner.
So, now we don't need a grid, and we can just say loading, and then I will reference my loading spinner. And, yeah, maybe that's okay. Let's give it a shot. And, yeah, we see it right there. So, let's do this. One more div. Let's see how quickly and sloppily we can get this to work. Let's do flex justify center. Yep.
Let's do flex justify-center. Yep. item-center, and then a little bit of a gap. All right. Let's give it a shot. Refresh the page. We scroll to the bottom. It takes three seconds to load in, so we see a loading spinner, and then once we successfully load that data, it gets merged in, and Vue re-renders the page. And you know what?
Refetching with Always11:42
load that data, it gets merged in, and Vue re-renders the page. And you know what? That's kind of all you need to know. Just the last little nugget might be, do you want to refetch this data every time we intersect? So, for example, let's open up the network tab one more time, and, yeah, you'll notice even though I scroll up and I go back down again, we don't make additional requests. It just happens exactly one time, which most of the time is probably what you want. But, yeah, you can maybe imagine a situation like a dashboard where, well, every time you go back there, maybe we should repopulate this section, especially if it's data that changes frequently.
go back there, maybe we should repopulate this section, especially if it's data that changes frequently. So, to simulate that, I'm going to go into my routes file, and we'll say, let's get into the sleep, and why don't we say topic in random order, just to simulate data changing or something like that, or new data coming in. It doesn't matter. Just something to change the output. Okay. So, if we switch back to our Vue component, right up here, I'm going to add the always prop.
So, if we switch back to our Vue component, right up here, I'm going to add the always prop. Now, we're saying, no, every single time, always when we reach that intersection, I want you to make this request. All right. So, now, go to the top of the page. We scroll down, and, yes, the first time, once we get there, you'll see a request in the network tab, but watch this. And, by the way, notice the first fake word is Ulam. Let's go up, and I go back down, and now we make another request.
And, by the way, notice the first fake word is Ulam. Let's go up, and I go back down, and now we make another request. And now it's architecto. Go up, go down. Of course, it works in multiple directions. Yeah. You can make lots of requests here, but this might be precisely what you want in certain situations. All right. So, congratulations.
All right. So, congratulations. You have now successfully mastered the ancient art of lazy loading data using the whenVisible component. So, now, even if you knew nothing at all about the IntersectionObserver API, you would be just fine. And you know what? For me, the time span between when I need to reach for that API is just wide enough every single time I forget how to use it. But, yeah, the cool thing is now I can ignore it entirely.
every single time I forget how to use it. But, yeah, the cool thing is now I can ignore it entirely.
