Playing
01. Infinite Scroll in Vue

Episodes

0%
Your progress
  • Total: 21m
  • Played: 0m
  • Remaining: 21m
Join or sign in to track your progress

Transcript

00:00
So in this snippet we're going to look at a common pattern that I use to implement infinite scroll in Vue. In fact this could be translated to pretty much any other front-end framework if you wanted to, but we're going to focus on Vue. We don't really care where the data is coming from on the API, but I'm going to show you that anyway through the course, so you kind of know where we're
00:21
pulling this data from, but let's take a look at the demo of this. You can see here that I've got these kind of fake articles, and I've brought up the network tab in my developer tools, just so we can see when these requests are being made. So if we head over to the API here, we've got a list of items. We've got some meta down here. Now as long as your API and your
00:43
pagination that you've implemented in your API is giving you the last page, that's pretty much all you need, as long as you can of course go ahead and actually choose the page that you want to go to. So I'm assuming that you are working with perhaps a framework that gives you this functionality, and I happen to be working with Laravel here. Okay, let's demo this out. We've
01:04
of course loaded in page one to start things out. We've got quite a short page here, of course until we reach the bottom, when we start to see page two loaded in, page three loaded in, and I actually have 40 articles in the database. So we're going to go all the way down to page four, and of course when we get to the bottom, we stop loading in content, which is really important. That's quite
01:27
tricky to get working nice and cleanly. So that's pretty much what we're doing. Whether you're working with Laravel or any other framework, you should be able to get this set up in your project really, really quickly, and it's such a simple pattern that you'll be able to recreate it when you need it again. Okay, so I've cleared everything out from the introduction. It doesn't matter where
01:47
you're doing this, whether you're doing this inside of a custom Vue built application, whether you've used Vue command line interface to build a project, or whether you're doing this in something like Nuxt.js. The pattern and the way that this works is going to be pretty universal all around. Now we're using Tailwind on the client side here just to demo this out, just so we've got a little
02:10
bit of height to each of these elements, so we have room to scroll. If not, just add some styles in there yourself. It doesn't really matter. Now the first thing that we want to do is make a request to our API to actually fetch a list of these articles, or at least the first page. So I'm just going to hop over to the terminal here and do an npm install on Axios. And just while
02:31
that's finishing, let's go ahead and import this and just make that initial request, just so we've got an iteration on this initial kind of component. Okay, so unmounted, that's where I want to do this. I'm currently just working within the kind of base app here, but this can be done within a component. It doesn't matter. And let's make sure we have some data within this component to store
02:53
this out as well. So I'm just going to say that we have a list of articles, which is by default an empty array. So for our methods, let's create out an async method here to fetch. And I'm just going to call this fetch. That makes sense for now. And let's go ahead and await on a call to our API. So let's go over and grab the URL to this. And we're going to tack on a page
03:21
number, but of course, later we're going to make that dynamic. So let's go ahead and assign this to articles. And let's set the articles in our component data to the data property from Axios, and then the data property from my API just here. So we should have a list of articles in there ready to go now. So I'm going to call fetch from mounted. And let's come up and just dump this out
03:45
just to make sure that we've got that list of articles first of all. And sure enough, we do. Great. Let's iterate over this component here to output this or this markup here to output this. So let's do a v4 article in articles. That makes sense. Let's make sure we give this a unique key. We do have an ID for each article. And that should be pretty much it to see a list of them
04:10
things. Let's just replace out some of this data here. So let's output the article title. And let's put output the article ID as well. Now, the reason I'm outputting the article ID is so I can see that the next item in the stack is correct. Otherwise, we might be loading in more than one page more than once, if that makes sense. So let's go ahead and if I can spell
04:34
description properly, output that description. And there we go. Great. We've got loads of room to scroll down here and keep an eye on our network request. So we're going to jump straight in and we're going to grab the view observe visibility package. What this allows us to do is on a particular element. So if we just head down here, use this directive here to invoke a method when
05:00
that particular element comes into view. And of course, for our list of items, we want to load more in when we can see the bottom of the page. So if we go ahead and install this, we'll see how this works in just a second. So let's make sure we of course, download this first of all. And let's just pull that in here very quickly. Now, really importantly, this uses the intersection
05:24
observer API. So you may need to go ahead and grab a polyfill if you want to allow this to work in browsers that don't support fully intersection observer API. I'll let you go ahead and do that depending on what you're building this for, who you're building it for, etc. Okay, so we'll just pull this in from the package and then just use it on view as a global plugin. And I can do that
05:47
over in main.js here because I'm using a Vue CLI built app. So let's pull that in, make sure we use that. And now we have access to that directive. Now, under the list of things that we're rendering, we're just going to have an empty div. That's all we really need for the purpose of this. So I'm just going to create an empty div here. And I'm going to go ahead and say view observe visibility.
06:10
I'm going to say something like handle scrolled to bottom. Now there are loads of things that you can do to customize this plugin. Go ahead and check out the documentation if you need to find out anything else. But let's go ahead and check if this method is actually called first of all. So just going to log something out in there and come over and give this a refresh. And let's open up
06:33
our console. Now you'll immediately see that when I refresh this, we get this logged out twice, which doesn't really make sense. The reason that this is happening is because Vue is not rendering this content directly or initially because it's not server-side rendered. So we get a kind of flicker of this data not being available. That's why we've got two calls to this method. And if we
06:58
scroll down, you can see we've got three, four, five, so on and so forth. But we've also got one when we kind of scroll up. So we're seeing this being logged out quite a bit at the moment. Now one way I like to get around this, at least the initial problem, is I like to attach a vif to this. So I'm going to say if articles length. This is only going to be shown when we have a list of
07:20
articles. And that means that when I give this a refresh, we're only calling this once just here, which helps a little bit more. Now the next thing we're going to do is we're going to bring into this method isVisible. What this will help us do is to perform a check with the intersection observer API. Check this and then return if it's not visible. So I'm going to say if not visible.
07:46
That gives us a little bit of a better result. So let's just log out ABC once again. Let's come over and give this a refresh. So you can see initially that is not being logged. And when we come down, that's being logged. When I scroll back up again, it's not being logged, which is great. But when I go back down again, it is being logged. So that has massively improved the
08:08
triggering of this method just by adding that check in there. OK. So now that we have done that, we want to basically have a page number that we increment when we get to the bottom of the page. Recall this fetch method. And then that will use the incremented page number. So we're going to add a page to one here. The first thing I'm going to do
08:31
is change this over to this page. And then I'm going to come down. And when we do hit the bottom of the page, we're going to increment the page. And then we're going to recall fetch. Now that is pretty much it. Because what's going to happen now is we load the initial content with page one. We get to the bottom of the page. We increment it. And then we recall page two. Let's head over
08:54
and see what that looks like. So let's give that a refresh. And let's scroll down. And at the moment, it doesn't look like that has worked. Now the reason for this is what we're doing is we're assigning articles the result we get back from this. What we should be doing is pushing new items onto this. So what I'm going to do is take the result from that. And I'm going to push on
09:15
the spread out version of that. Now these will be in an array. So we're spreading these out and pushing each of these objects onto the article stack. Because of course, we want to go from 1 to 10, but then add onto the top of the results that we already have. So let's scroll down now. And when we get to the bottom, we should see 11, 12, all the way up to 20, and then so on and so
09:39
forth, all the way down to the bottom. Now that looks like it's working great. But if we just head over to the Networks tab, you can see that I'm actually making page requests to things like page seven, which don't actually contain any data. So if I carry on going down to the bottom of the page, we're really unnecessarily making a huge amount of network requests to our API. That's not what
10:02
we want to do. So from the introduction, like I said, we're going to use this last page value here. What that will allow us to do is not increment the page beyond the last set of pages that we have for the data in our API. So to do this, we're going to go ahead and store the last page just in here. We're going to set that to one initially, because we would assume that we'd always have the
10:26
last page set to one, we'd always at least have one page. And then when we get the result back from our API, we can actually update this value. And that will update every time we fetch. So let's go ahead and say meta last underscore page. And that will then update to the value of four. So now what we can do is inside of here, just after our visible check, we can use another check
10:49
to again return if a condition is met, which will be if the page that we're currently trying to access is greater than or equal to the last page, e.g. five, then we don't want to increment the page. So if we're on the last page, e.g. four or five, then don't do anything. So now the difference is clear. If we go ahead and check the network tab out, we scroll all the way down,
11:15
we see two, three, and four. But we don't go any further, because the last page is four. So there's no point even making a request to page five. So that's pretty much it. That's the pattern. It's pretty straightforward. Of course, you can code this up how you like. This is just the way that I do it. But that's the general thing that we want to do. Handle scroll to the bottom,
11:36
increment a page number, and load more information in. Now just before you go, if you do want to hang around, I'm going to show you how to kind of take all of this, put it in a separate view component so it's a little bit easier to reuse. So we're going to look at a way that we can make this a bit more convenient to reuse throughout our application. So if you've got lots of places
11:59
that you want to implement this, you kind of don't have to implement this here. And the handle scroll to bottom every single time you need to use this in every page of your app. So let's go and create a component to make this a little bit more reusable. So I'm going to call this infinite scroll. And we're going to go ahead and just pop out a template here really quickly with just
12:25
scroll in there for now. Let's go ahead and load this into our page. In fact, let's create a new page for this just so we don't lose what we've already got. I'm going to go ahead and rename this to app zero. And it's going to create a new app dot view file in here and paste that in. So over in app then let's go and pull this in. I'm actually going to get rid of all of this.
12:48
Let's go ahead and put in that infinite scroll component. And let's import this just up here. So let's just pull that in from the components directory and infinite scroll. And let's just add that to our components list in our template. Great. I'm actually going to get rid of all of this as well because we've
13:12
got a reference to it in that other page. So I might as well start from scratch and work our way up. Great. So we've got that component in there. Now the purpose of this component is going to be for us to pass a list of items in, iterate through them items, but have the scroll handler within here that emits an event to tell us that we need to re-fetch data and
13:38
re-pass a list of items in. So this is going to be a generic list of items which means it could be articles, it could be users, it could be absolutely anything. So let's head over to that infinite scroll component, pull out our script section, and let's accept a prop in here of items. It doesn't matter what they are. They are required though and we're going to set the
14:00
type here to an array even if it's an empty array. Okay so what I'm going to do is I'm going to not self-close this component. Instead what we're going to do is iterate through them items in here and use a slot which will allow us to render for each item however we want to render this. So inside of the infinite scroll let's do a div in here and let's say v4 item in items
14:30
let's key these by an item id. This is the only place that you could find this a little bit tricky if you don't have an id for a particular item then you might not be able to use this but we'll just assume that the api content is very similar. So we're going to have a slot in here and the name for this slot is going to be item. What that will allow us to do is inside of here
14:53
create out a template and within that template choose what we want each of these items to look like as we iterate through them and what we're going to do is we're going to do a vbind on that item that we're iterating through so we get that in the slot scope of the thing inside of our component. Now we're not working with any data at the moment so we can't even see if this is working
15:15
so let's go over to our app zero page here and let's just bring back our articles in our data here let's go ahead and return that and let's grab this fetch method as well but we're going to keep this super simple so let's create our methods and let's just go ahead and make a request to yeah let's keep our page in there as well and let's just yeah push them articles here and then
15:49
let's say that when this mounts we're going to go ahead and fetch that information so the items that we passed through as that prop are going to be them articles and then what we can do is like I said with that template and that slot and the slot props we can go ahead and receive for each of the iterations that data in here so on this template
16:08
what we can now do is we can say vslot item and we can pull out that item here and then let's just dump this out for now so we should see basically each of them articles listed out on here now we've got a little error here we've got a missing prop that needs to be items and there we go so for each of them we're outputting the item that we're iterating through inside of this component all
16:33
that means is we can go ahead and take the markup that we were previously using and we can pop that within here the functionalities tucked away inside of our infinite scroll component to allow that to tell us when to refetch this information but we can style this each of the items up as we like now this is called item so I'm just going to switch each of these over to item and we should
16:58
be good and we should have exactly the same thing and the only thing we're not seeing is when we get to the bottom of course that re-trigger but that is exactly what we're going to do but internally to infinite scroll so again let's come into app zero and take this and let's pop this just at the bottom here and we'll say v if items dot link this time we'll still implement
17:20
the handle scroll to bottom let's go ahead and grab that but the only difference now is what we're not going to do is call the fetch method we're going to emit an event from here so let's go ahead and emit an event and we're just going to call this refetch for example and we want to say what page we want to refetch from now at the moment we're handling the page from outside of
17:44
here but it'd be a good idea if we took this and handled that internally to the infinite scroll component so let's go ahead and create out data in here to hold this and let's go ahead and say let's get rid of this line for now and let's reference this page and we can increment that page and that's just about good to me so what this now means is that refetch will allow us to outside
18:09
of this go ahead and say well when we need to refetch we can just call the fetch method but that will accept in now because we've used the page in here that would accept in now the page that we want to call we can reference that from here when we initially fetch that we can fetch page one so let's just run over this really quick before we tidy this up so we've got a fetch
18:36
method which accepts a page in we fetch page one then over in infinite scroll we always assume we're on page one to start with although you could accept that in as a prop if you wanted to that goes ahead and iterates through each of the items allowing us to customize the item via a slot and the slot props that we've got here so we can actually grab all that api information out
18:58
we've got the v observe visibility uh directive in there to handle scroll to bottom which increments the page internally and then emits that incremented page so if we just give this a refresh we should see i think there's going to be an error yes we've got this emit is not a function just go ahead and make sure we don't assign that and let's come up scroll down and there we go
19:23
that's working in exactly the same way but just doing this this really small change allows us to just not have to fiddle around externally with handling scroll to bottom we can just really easily use that functionality now we need to figure out what to do with the last page stuff that's a condition that might be best left outside of this particular component so for example that
19:47
might be handled in fetch we might want to still keep the page number in here or the last page number so we might want to say last page one and then always update that so set last page to articles data meta last page so we still keep that up to date but then we check the page that we're requesting against this last page so we do that inside of fetch rather than inside of here
20:18
so let's go over and just check this out and make sure that's working it doesn't look like it's working at the moment so let's have a look here and of course we've put greater than or equal to one is equal to one so that doesn't make sense let's go all the way down to the bottom keep an eye on our network tab and yeah so we're not making any additional requests when we reach the
20:36
bottom great so that just about wraps it up of course there's nothing wrong with going with a first approach that we looked at and just doing this all on one page if you just have one or two pages that do that it's probably fine i think wrapping it very lightly in something like this makes sense so you can reuse this a little bit more conveniently like i said without having that
20:55
handle scroll to bottom every page that you want to use this you've just got a little bit of simple fetching going on and then all of that is handled by this infinite scroll component with that slot and slot prop which allow you to completely customize the output for each of the api items so there we go infinite scroll in view whichever way you want to do it
1 episode 21 mins

Overview

Here's how to implement a simple, clean pattern for infinite scrolling content in Vue. We'll refactor to make it more reusable, too.

Alex Garrett-Smith
Alex Garrett-Smith
Hey, I'm the founder of Codecourse!

Episode discussion

No comments, yet. Be the first!