Transcript
00:00 We're going to dive deeper into optimizing rendering. So first, I want to talk about the render or the React rendering cycle. So we have a render. I think we've established that so far in this series of exercises. And there is this phase when after React
00:19 has called your React component, your function, and gotten all those React elements, there's this phase where React has to reconcile the old React elements with the new ones. Now, if it's the initial render, then React doesn't reconcile anything. It's like, oh, this is brand new stuff. And so we're going to update the DOM to reflect that.
00:36 But if we are re-rendering because of a state change, then we need to look at the old UI elements and compare it to the new ones. And that process is called reconciliation. And once we've reconciled the differences, we know what DOM updates need to happen. And that's where we get into the commit phase.
00:53 And this is where we actually update the DOM for the changes that have occurred. And this phase is actually kind of interesting because you could have multiple renders and multiple reconciliations before you actually get to a single commit, in particular when we're
01:11 using concurrent features like use deferred value and transitions and things. So once the DOM has been updated, that's when your use effects are going to be called and all of that stuff. But then state changes again. And so we're going to re-render. And we get through reconciliation. We commit. And the cycle continues until the user closes your app.
01:30 And this process itself, like React, is really quite fast. And there's not a whole lot that you need to worry about optimizing most of the time. But sometimes there are unnecessary renders, and your render is slow. And you want to avoid those unnecessary re-renders.
01:48 This is why I say it's important to actually fix the slow render before you fix the re-render. Because if you have a render that's slow, then eventually your render function does need to be called. Something did actually change. And you do need to update. And you want that to be as fast as possible.
02:05 So sometimes people will say, oh, I'm going to re-render or I'm going to eliminate all unnecessary re-renders. And that's going to improve my performance. And it probably will. But what if you could speed up your re-render so that it happens quickly, or speed up the render itself
02:24 so that happens quickly. And then you realize, oh, the re-renders are actually not that big of a deal. So always focus on figuring out why is my render slow and try to optimize that rather than trying to reduce the number of times you're re-rendering. A good example of this would be when we were doing the calculation for the matching cities.
02:44 And we wrapped that in a use memo. And that made the render a lot faster. So just as a quick example. So there are a couple of things that can cause React to trigger a render on your component. So the props can change. The internal state of the component could change.
03:02 If we're consuming context, that changes. Then that is going to trigger a re-render. Or if the parent re-renders, then that's going to trigger a re-render. But that's not exactly always the case if you're using the memo optimization, which we're going to be exploring deeper in this exercise. So just as a bit of a review, we've got our count button
03:22 here, we've got a name here, and we have our app right here. So we've got our name and our count and an increment function. And we're rendering the count and the name and displaying some data based off of that. So if we wanted to optimize this, we could pass these in memo or pass the name input in memo.
03:40 And now the name is not going to re-render when the count changes because it has been memoized. So it's receiving the name. And on name change, if the count is changed, then that is not one of the inputs. And so React will say, oh, none of the inputs changed. So we won't bother re-rendering.
03:58 So that's a simple case. But things get a little bit more complicated when, if we were to try to memoize the count button, that one wouldn't actually work because we're passing this increment function, which is getting recreated every time. So now you have to memoize that with useCallback, which is a big pain.
04:16 And of course, the React team is, at the time of this recording, they're working on a compiler that will automatically handle all of this stuff for us. So it's possible that this won't be totally necessary for you in the future. That's still very experimental right now. But maybe in the future, we won't
04:35 have to worry about this quite as much. But for older codebases, or even the codebases of today, we do need to worry about these things. And so if you want to reduce the re-renders, you need to memoize things. But then you have to, like, that spiders out to everything. So this is, again, why I say fix the slow render
04:53 before you fix the re-render because fixing the re-render, reducing unnecessary re-renders, is going to require a lot of manual work today, which is kind of a pain. So the other thing I wanted to mention about this, too, is that memo accepts a second argument. So we can pass another argument here.
05:12 And it's a special function that we're going to be implementing in this exercise. It allows you to customize the way that the memo utility compares the previous and the next props. And so this helps a lot with really seriously fine-tuning things. You don't typically use this.
05:31 I have not actually shipped anything to production that uses this particular API. But in a scenario where you have just a million instances of a component or something, it can be kind of helpful. We're going to explore that argument. But then we're going to explore how we can change our code a little bit to not need the argument.
05:51 So this is going to be really interesting for a lot of you, I'm sure. All right, I think that's enough. Let's get into it.