This episode is for members only

Sign up to access "Building Reactive Realtime Applications with Livewire" right now.

Get started
Already a member? Sign in to continue
04. Adding fast infinite scrolling


So the goal for this episode is to get infinite scrolling working but we need to be really really careful about how this re-renders. So we want to look at the reactivity of the entire component which shows all of our posts and make sure we're not re-rendering too much every single time we
scroll down and load more posts. Now the first thing that we're going to do is look at a really simple basic implementation of this and then we're going to switch over to chunking these and I'll show you how to do this. Now before we do anything we're going to go ahead and pull in the alpine intersect plugin which allows us to use the intersection observer api to detect when we're
at a specific point in the page. You could have a button for this whatever you wanted to do but we'll make this quite nice. So we're going to go ahead and pull in the intersection api plugin from alpine and then really importantly to register this we need to manually bundle livewire and alpine into our app so we can actually register that plugin. So the first thing that we're going
to do is go ahead and grab this directive just here and we're going to add that to our app.blade.php file just down here. We can do that anywhere just at the end of the body and then we are going to go ahead and pull livewire and alpine in manually into our app.js file and then we're going to go ahead and start livewire but in between that we can go ahead and register this plugin. So if we
head over here this is how we register it so let's import it first at the top and let's go ahead and use alpine plugin intersect in between there and now we've manually bundled everything and we won't get any conflicts from livewire's alpine version and our own alpine version. Okay so now that we've done that we've got this on the page let's take a look. Okay let's open up our post index and see
what we're doing here at the moment we are just outputting a list of posts now let's come up with a really naive approach to infinite scrolling first and then we'll switch over to our solution. So we're currently just getting all posts which is not what we want to do let's go ahead and add a limit to this so let's say we have a limit of 10 and then we go ahead and get this and
the actual fact i'm going to change this to take so that in itself will just render the first 10 posts pretty straightforward now what happens if we were to keep track of this within an integer up here so let's say per page or let's say limit and we will set that to 10. Now what we could do is take that and set the limit in here which of course still works but then we could just increment this
limit so let's take a look at how this works and then we'll see what the problem is so let's call this increment page just to keep things simple and let's go and set the limit to the limit that we have plus 10. So now when we invoke this over in our post index using the alpine plugin down here so let's go and say x intercept
increment page what we should find if we just add x data to that what we should find is it just increments this when we get to the bottom of the page so if we scroll down here it's not actually doing anything so let's just check our console here and yeah we just need to say wire increment page and this isn't working now because we haven't keyed what we're outputting so let's
make sure we are doing this so let's add a wire key to here and that's just going to be the post id in here so let's make sure we output that post id and we should be good okay let's start to scroll down and as you can see more results are getting loaded in now the problem with this is first of all if we just check out our network tab and see what's being re-rendered here let's just go right
down to the bottom again you'll see that we are re-rendering every single one of these items which is not good these are pretty simple at the moment but the more complex they get and if we have even further nested live wire components inside of these things are going to get really really complicated so this is not a good solution nor is it a good solution to push to sort of collection
every single time you increment the page that's going to end up being very slow also what we're doing here is we are putting a lot of strain on our database because at the end let's say we had a thousand records if we scrolled all the way down to the one thousandth record in the database this is going to be pulling in 1000 records with our database query and everything is just going to
get really really slow so we're going to completely scrap what we're doing here and we're even going to get rid of the post just inside of here and i'm even going to go ahead and get rid of the post just inside of here i'll just comment them out for now and we'll get rid of this as well so the approach that we're going to take here is we are going to chunk these records but we're only going
to show the id within each of these chunks so let's think of it like this we're going to have a chunk with one two three four five let's say that we were doing five per page then we're going to have another chunk in here with six seven eight nine and ten and so on and so on until we get to the last batch so we're going to build up an associated nested array of these chunks now we're
just we just then have a big chunk of ids not very slow arrays are pretty fast so we'll just have a big chunk of these ids what we'll then do is we will only render out these chunks and fetch these from the database as we need to so let's take a look at how we do this so we're going to store up here an array of chunks and we'll just set that to an empty array for now
and when this component mounts we then want to grab all the chunks so we're going to go ahead and set the chunks in here to post latest so we can still scope this by the latest now we only want the id from the database we're going to make one big query here but we just want the id back so even if you had 10,000 records we're just getting back 10,000 ids so it's not going to be
a huge problem then we're going to go ahead and chunk these by 10 so that's how many we want per page and then we're going to grab these as an array now what i'd recommend you do if you are building something like this where you have an infinite scroll probably limit it to some point so you'd want to go ahead and limit this to a certain amount of records maybe a thousand
it really is up to you okay so once we've mounted this not mount this let's go over to our post index and just dump out on the page these chunks just so we can see what we're doing in fact let's do this in our component so we can see this a little bit better so let's dump the chunks just so we're completely clear on what we have here so we've basically got batches starting at 100 going
all the way down for each of the records that we want to display so what we can now do is we can iterate over these chunks but only show them when the chunk that we should be showing should be shown based on the page that we're on and that is what gets incremented so if this doesn't make sense bear with me so we're going to go ahead and actually create out in here a page that we want to
be on this isn't like typical pagination page is going to match up to the current chunk that we are dealing with so what we can do is over in our post index we can do a for loop so we can do this directly within blade and we'll use the value in here we'll just call this chunk and we want to iterate over here while the chunk that we're currently going through is less than the page
that we're on so let's go and say chunk plus plus we'll end the for loop there and then inside of here i'm just going to dump the chunk out just so we can see what we're dealing with so let's say var dump and we'll say chunks which is within our component and then we'll get that chunk so what this will do is it will show the first chunk because we're starting on page one and zero is
less than one it will show the first chunk but when we increment the page it's going to show the second chunk and we're going to end up with a bunch of chunks every time we increment the page so this increment page method now which we are going to bring back will do the following and this is going to be a little bit weird at the moment because we have an intersect in here
so we might need to just put a temporary button to go to the next page so let's just say increment and we'll wire that up to increment the page and let's just get rid of this for now because we're not showing anything out here okay let's go over to our post index and we'll bring back that method to increment the page so let's say increment page and we'll just say this page plus plus because we
just need to increment that by one okay let's check this out on here so i'm going to click increment we've got the first batch of posts that we want to load through second batch comes through third batch and so on and so forth so we're loading these in in individual batches now the way that we can make this fast within livewire specifically is only render out a component within
this batch when it needs to be rendered so basically what we're doing is we're not re-rendering the rendering the entire list of posts we will have a component in here responsible for taking these ids fetching them out the database when they're visible and then showing them and therefore the entire page will not be re-rendered because we're just going to be pushing a new component to the
page effectively so let's go ahead and create that component out which deals with that and then everything is going to start to come together and hopefully make more sense so we'll go ahead and make out a post chunk component and let's go ahead and instead of our dumping over here we will use that component so we'll take what we've got here because we need to pass them ids through to that
component and let's say livewire post chunk and we'll go ahead and pass the ids through into here as an array we'll not forget to key this so let's key this by the chunk itself because that's going to be unique because it's going to be zero one two three and whatever and we'll pass the chunk through as well just in case we need that just so we have that in there okay so over in our post
chunk let's open the template and let's open this let's accept the ids through into here so that's going to be an array of ids and then we'll just dump these on the page here just so we know that this is all coming together so var dump and ids great okay so this shouldn't look any different because we're just doing the same thing but within a separate component but now that we've got an
individual component here that's responsible for only rendering when we get these in what we can do is grab these from within our render method so this is a little bit trickier we want to grab our posts out in here and we want to say post we can say latest here because we're always ordering these by latest but i'm going to show you a way to do this with a raw query in just a second so let's
just do this for now so we're going to say we're in ids this ids so we're only fetching these from the database when this component renders with the ids that we want to show and then we can just say get okay let's try this out so we know that over in our post index this is where we were outputting our post before we don't want to do this now index now we want to do this over in our post
chunk when we iterate through them so now in here we can say for each posts as post and in the for each and put that inside of there and i'm just going to switch this over to a binding just to make this a little bit more consistent and there we go okay so if we head over now and give this a refresh uh yeah so let's just fix up id there we go so we get the first batch of results
in here we press increment we get the second batch of results in here and so on and so forth so i'm going to get rid of that increment button now and we'll do that over in post index we'll bring back our intersection observer api and let's just see what this looks like and i'll go over this whole thing in just a second because it can be a little bit confusing so let's scroll down and you can see
that this is just working really nicely now the difference between the solution that we kind of had before and this solution is that let's check our network request here and let's scroll down here and get right to the bottom of the page okay so we're at the bottom of the page here we've got an issue because we need to stop this at some point which we'll do but let's look at the last
one now before the issue we had is that because we were just pushing more records to that entire list of posts what is happening is livewire is then re-rendering the entire list of posts now what we have we do have all the ids here but you'll see that these just represent the latest 10 so it does look like there's a lot in here but all of this markup is just for the last 10 results
this was from the one before that so all of these requests that we're making are the same size pretty much and the time it takes for each of these requests to be made should be very consistent as well even when we get to the thousandth record or the ten thousandth record the only thing that we have accumulating here is the list of ids up here which shouldn't be too much of a problem
so that is how we solve the issue of infinite scrolling with livewires reactivity when we re-render a list of the pages that we have so it's not really a reactivity issue but this is really really important stuff okay so we'll fix up the issue with the last page here and we'll do that over in the post index and we'll go and create out a method in here
called has more pages that will just tell us if we're on the last page or not and to implement this we just want to return and check if the page is less than the count of the current chunks that we have because our chunks are kind of like pages so this chunks and we'll count that and now what we can do is over in our post index just put an if statement around this and call has more pages
end that out and let's just check that we can scroll all the way to the bottom without any issues so let's go all the way down here to the bottom and yeah we're not making any more requests so we don't see that issue the last thing that we're going to do is just change around the styling here because we've introduced some inner components so we've got a space y of eight here
but we need to do that inside of our post chunk as well so let's do this just here and they should all be nicely spaced out now great okay so hopefully that makes sense if we think of it like this we want to only render something when we have new data we don't want to render anything else the first batch that we get obviously gets rendered the second batch we get gets rendered but
that doesn't re-render the first batch because we're working in batches where we're just rendering the 10 ids that we need and that's a really important concept so let's go over to our post item get rid of our id because we know that this is all coming through properly but i'm going to show you in fact i'm not going to get rid of that now because i'm going to show you how to order
these a little bit better so let's go over to our post index we know that when we grab these we're using the latest scope but inside of our post chunk what we're doing is also using latest now if we needed to change that around at any point we'd have to change this in two places which isn't a good sign so what we're going to do is we're going to switch out the latest scope and we're
just going to order this at the database level by the order of the ids we've been given so when we do that initial latest query that will give us back the ids in the correct order and we want to order it by the order within that array hopefully that makes sense so to do this let's just bring down what we've got here first of all and we are going to order this by a raw query and that query
is field and let's just put these in double quotes so we can pop what we need inside of here we're going to order by the id field given a list so this looks like this one two three so it would order it by this not by the id but it would order it in the order we give it based on that array so we can go ahead and take this and just implode by a comma which is what that mysql function needs
the list of ids that we have so this ids so that will just then order it by the order we get given in that array so let's head over and give this a refresh and you can see if we just scroll down here sure enough it's in the same order but now the benefit of this is that over in our post index if we want to scope this by the oldest we don't need to make any changes anywhere
else this will be automatically ordered properly for us okay so now that we've done that we've implemented infinite scroll and this adds a real layer of complexity onto what we're going to do because remember when we get a new post in we're going to push it to the top we need to push it to that first chunk but when we go down and we delete a post somewhere we need to tell livewire where
this chunk is and how to delete this and we can use reactive for this which we're going to do later but we're going to come across some issues so let's go over to our post item lastly just get rid of this id and there we go we have infinite scrolling and we can start to add all of the other functionality we need like our real-time stuff
12 episodes1 hr 43 mins


Livewire can react and re-render anywhere you need it to. But what if we have a infinite scrolling timeline of user posted content with updates in realtime? With added reactivity, we need to be a bit more careful about performance.

Let’s build this together, making sure we keep things running smoothly along the way.

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


No comments, yet. Be the first to leave a comment.