This next performance tip is probably the most important of the series.
00:05
It's also the most difficult to try and come up with an example with and it's also the most difficult to realise that you could do this in pretty much any type of component. Now this tip involves watching for a side effect, a re-render side effect, on other components when you don't intend them to.
00:26
Now we know that Livewire components re-render themselves when something happens, which is absolutely great because that's what makes Livewire so good. But if we have unintended re-renders based on things that we do, we're going to end up with a huge amount of requests to our app.
00:43
And this is probably the thing that most people struggle with when they're working with Livewire. They have way too many requests being sent to the back end and this slows everything down. So what we're going to do is we're going to build out a component that I built out for myself and had this exact issue with.
00:59
And hopefully from this you can take this and apply it to your own apps and watch out for the same problem. So we're going to go ahead and create out a nest of comments. So we're going to have a parent comment, then we're going to have children under that comment,
01:13
and we're going to have children under that, e.g. replies. So let's go ahead and create out this simple component. We're not going to set the database up because we don't want to waste too much time. But let's see how this might look in a standard app.
01:24
So I'm going to go ahead and create out a comment nest component. I'm also going to create out a comment nest item component, which will be each of the comments, including the children. And then I'm also going to create out a item action component.
01:39
So this will be something like a delete button, an edit button, anything that modifies an individual comment. Now you might not have all of these components, but the same concept applies. So let's go ahead and create this out, comment nest.
01:53
And inside of this comment nest component, we're just going to kind of mock a list of comments that might come through from the database. But we're going to just have these as a standard array. So let's go ahead and create out this comments array.
02:05
And in here, we're going to have individual comments. We're going to give these IDs, just kind of like the data we'd get back from the database. So I'm just going to say comment one. And then each of these comments will have potentially children.
02:19
If they don't, it will be null or an empty array. So for this first comment, we're not going to have any children. But for this second comment, comment two, we're going to have an array inside of here, which represents more children.
02:32
So these are the comments within this. So again, we're going to have an ID in here, that's going to be an ID of three. The body here is going to be comment two, child one. And the children for this will be null.
02:51
So let's just say null. And then we'll have another child to this comment, which will be comment four and comment two, child two. I think that'll do just for now, because that will give us enough data to work with.
03:05
Now, just before we start, the entire idea around this is if, for example, we edit or delete or do anything to this comment four, we don't want any of these other comments to be re-rendered. And there are certain instances where you may see a re-render
03:24
in all of these comments with just one action. So that is what we are going to demo. So let's go over to the comment nest component template. So we can go ahead and just start to output these.
03:35
Again, we're just working with array data here. So this is going to be really simple. So let's just say comments as comment. And then we're going to end the foreach loop here.
03:44
And then inside of here, we're going to have an individual component that we've created, which is comment nest item for each of them comments. So we're just going to pass the comment down as we would. Of course, we've already spoken about passing huge objects here,
03:58
but we'll just keep things simple. And really importantly, as with any foreach loop in Livewire, we're going to key this by the comment ID. So Livewire knows how to keep this up to date and keep this in the right order.
04:10
OK, so over in comment nest item then, that is where we're going to accept that comment in and output it. And also output is children. And we're going to do that recursively.
04:19
So let's just go ahead and say comment. And then in comment nest item dot blade dot PHP, we can go ahead and output the comment information here. And in this case, let's just keep it simple and output the body.
04:33
And we'll also output the ID next to that as well. So let's just switch that up. OK, so if we just come over and give this a refresh, we've got comment one and comment two.
04:42
Because over in our comment nest, we just have two top level comments. Now we want to recursively iterate through the children. And if these children have children, we'll also see them appear as well. We might look at that at the end of the video.
04:58
But we want to output the children as well. Now to recursively do this, we just want to go ahead and first of all check if we have children for this comment. So we'll just say if comment children and the if statement there.
05:10
And then inside of here, we want to iterate through the children and render this same component. And that gives us a kind of nested comment stack. Now just as a kind of side note,
05:20
if you were going to go ahead and implement a nested comment system, it was not a good idea to pull this data without using some sort of adjacency list or something like that. But we can cover that another time.
05:31
So let's go ahead and just iterate over these comments. So comment children. And we'll call that child. End the for each loop here.
05:40
And then let's go ahead and use the same component. So I'm just going to put a div in here and add a class of margin left 6 just so it kind of pulls out from the side of it so we know it's a child. And again, we're going to reference the same component comment nest item,
05:53
which is this component that we're currently in. So we're going to go ahead and pass the comment through as that child. And again, because we're using a for each loop, we're going to go ahead and key this by the child ID.
06:05
So what we get by doing this recursively is the first comment, the second comment, and the children of the second comment. And like I said to you, if we just come over to comment nest and this third comment here did or this fourth comment did have children,
06:20
let's just grab the structure of this one, that would also then render that out as well. So let's just pop that in there just to test out. You can see there we go.
06:29
So we effectively get an unlimited amount of nested children. We'll leave that as null, though, because this is enough data to work out what we're doing. OK, so now inside of comment nest item, we want to put that action.
06:42
That might be to delete the comment, update the comment, anything that hits a Livewire component. It could just be kind of an edit toggle. So we're going to go ahead and say Livewire comment nest item action, like so.
06:57
And we'll go ahead and pass just the comment ID down to that, just as an example. So comment and ID. Let's go ahead and open up the comment nest item action file for this. And we'll go ahead and accept in the comment ID here,
07:14
which we can use, of course, to look that up in the database if we need to, but also emit an event if something happens. OK, so if we come over to the nest item action blade file, let's create out a button in here that says do something.
07:28
Like I said, that could be delete the comment, edit the comment. And when we go ahead and use wire click on this, we want to go ahead and do something inside of that action component. So let's open that nest item action component back up.
07:42
And let's go ahead and say do something. Now, the question is, how do we know if any of these are re-rendering? And this looks a little bit odd at the moment. So we, yeah, let's leave it like this.
07:53
We kind of get the idea. In fact, let's change the color of this button so it's a little bit more obvious what we're doing. So let's just set the text here to indigo 500.
08:05
If I can actually type indigo 500, there we are. OK, so when I click on comment one, that has sent a request through to our back end because we're calling a method on a live wire class. That makes sense.
08:18
We already know that. But how do we know if that component has been re-rendered? Well, what I usually do is over on, say, the comment nest item here, I'll go ahead and just output the current date and time, including the seconds.
08:32
So if we come over here and we just click on this, you can see that none of these components are being re-rendered. We're sending a request through to the back end, but nothing's happening. Now, let's say that this do something button edited the comment.
08:46
Well, let's go over and listen for this and go ahead and refresh the component. So there are, of course, lots of different ways to do this, but this is the way that we're going to look at so we don't run into any trouble. So when we do something within a component,
09:00
maybe we have some sort of emit in here. So we emit an event. And let's just say comment updated. And then we want to pass through the comment ID.
09:09
So let's say dot. And then let's append on this comment ID. So when a particular comment is updated, we want to emit that and we want to give the ID.
09:21
Or we could just go ahead and say comment updated and this comment ID. Let's leave it at that for now. And then we'll see how this will affect us. Now, when a action updates a comment like this,
09:36
what we could do is listen for that and then just refresh the component or reload the component. So let's go over to our comment nest item live wire component. And let's go ahead and listen for this and then just refresh this component.
09:49
So if we edit a comment, of course, we want to refresh the component. Maybe you have markdown being used on the back end to render this out. So let's go ahead and create out our listeners inside of here. And we could do one of two things.
10:02
We could say comment updated and then specifically give a method in here. Or we could just leave it as comment updated without the dot and have that as a method called. Let's go ahead and just say comment updated.
10:18
And then let's create our method in here called comment updated. Maybe that took the data that's been updated and set something within here, within the comment, reloaded the comment from the database. It could be absolutely anything.
10:31
So now that we've got our timestamps in here, let's see the difference that this has made. When I click on this, you can see that all of these comments are being re-rendered, which is not good.
10:41
Because we're using the same component for every single one of these comments, when we listen for that event, all of them update. So we're sending potentially huge amounts of requests just because we want to reload or do something within an individual comment.
10:58
Now, whether you've come across this problem or not before, as you start to build bigger livewire applications, you are going to run into this issue at some point. What we're going to do in this part is look at how we can do a very similar thing
11:10
to what we want to do, but do it in a way that doesn't send a huge amount of requests. So let's take a look at how we would do that. So let's speak about the goal first of all.
11:19
So we'll go back to here. So when I do something to this comment one, I want only this comment to be reloaded, or I only want to do something within this comment.
11:27
When it's comment two, I only want it to be comment two. At the moment, whatever comment we use is updating all of them because we've got a listener for just a global comment updated, which will reload the component with this method call,
11:41
even though we're not doing anything inside of it. So the way that we can get around this is kind of what we just looked at a minute ago. When we emit an event, we're going to add on the ID specifically and listen for this specifically.
11:53
Now, there are other ways you can kind of get around this depending on how your data is structured. For example, you can emit up to only parent components. In our case, with nested comments, that's not quite going to work.
12:04
If I click on this one, you can see that only this one is updated. Great. This one, only this one is updated. But when I click on this one, you can see that this comment and this comment because it's a parent is also updated.
12:17
So that could be a solution just using emit up. But a really good way to get around this is to only emit events with the specific ID that you're listening on. So for example, I can emit comment updated dot this comment ID.
12:31
Now, that's a very specific event name for an individual comment by its ID that we can listen for. So what we're going to do now is listen for this specific event name. Let's go over to comment list item.
12:46
And the problem that we have with this protected listeners property is we can't really add in this comment ID or this comment ID in this case in here. If we come over and just give this a refresh, constant expression contains invalid operations.
13:04
So the alternative to declaring out a protected listeners property is to create out a method called get listeners, which we can then return an array from that looks like this. So we can practically take this,
13:22
and I'm actually going to put this back to how it was before, but then just comment this out. We can put this inside of here. So that is now valid because we're using this comment ID within a method.
13:35
So let's go over and just give this a refresh. That works. Now we're listening for only the individual comment ID. So from any child components, e.g. this action here,
13:45
we're only listening on that ID. Let's go over and give this a go. So click on this one. And it doesn't look like that's worked.
13:52
So let's just figure out why. And I think, yeah, we just didn't add a dot in here under do something. Let's try that again. Click.
13:59
That one gets updated. Click. And there we go. So now only the comment where we have a child component,
14:08
which is emitting that event, is being listened on with that specific ID. And only that component is now being updated. There are lots of different ways to handle this,
14:18
but I found that this is the best thing. When you're emitting events to components that could be used more than once, make sure you're being very specific about the component that needs to be re-rendered by that unique comment ID or whichever kind of model data you're working with.
14:33
So now what we can do is over in our comment list item, when we call this comment updated method, we're still going to get the comment ID through from here, like so. We can die dump on that just to see.
14:44
So let's say comment ID. Come over and give that a refresh. There we go. That's comment one, two, and so on.
14:51
And we can do anything in here. We can reload this comment if we wanted to. So we could reset this comment to something completely different. Now let's try that now.
14:58
And that will kind of bring the example together. So over in our comment nest, let's just grab ID of one. And let's go over to our comment nest item. Let's set this comment to this new array of information.
15:15
Still going to have the same ID, but the body might be an edited body. There we go. Let's go over and give this a refresh. Now when I click on this one, this value changes.
15:26
We've only made one additional request to this to get back this new item. So a really tricky one to demonstrate, but hopefully this makes sense. When you are particularly emitting events, and you're picking them up as a global kind of single event
15:42
without a unique ID attached to them, you'll likely find that you'll have a massive side effect of lots of different components being re-rendered. That means a huge amount of requests being sent through to your backend.
11 episodes•1 hr 22 mins•3 years ago
Overview
Building powerful apps with Livewire is a breeze, but as your app grows, you may run into performance issues. This series covers tips and techniques to keep your Livewire apps speedy.