Lesson Description
The "Local State Exercise" Lesson is part of the full, React Performance, v2 course featured in this preview video. Here's what you'd learn in this lesson:
Steve instructs students to practice using the repo and developer tools while building muscle memory. He discusses identifying unnecessary re-renders and optimize components by pushing state down the tree, explaining the trade-offs between performance and complexity.
Transcript from the "Local State Exercise" Lesson
[00:00:00]
>> Steve Kinney: So, what you are going to do is we're going to go over, there is another example waiting for you, and again, we're starting off easy on purpose, which is we'll control C this, which is the npm run examples. And we have this one over here called local state. You take a lucky guess what the assignment is, right? There are components right now that doing anything, components that shouldn't be related to each other.
[00:00:28]
That doing anything re-renders everything, right? Your job is just like build some muscle memory, get used to the repo. I understand it's pretty easy exercise I'm giving you, but like, let's get our blood flow and our muscles warmed up. And our goal is to at least go through the exercise of playing with the developer tools. Like don't just look at the code and be like, I understood what he said. I can just go through the motions for me so that when they get harder, you've built up the muscle memory.
[00:00:57]
And we're going to seek to take some of that state and push it down just a wee bit. What if I need to use the input value in a parent component, for example, in a useEffect API call? Should I use something like a useRef to retrieve the value when that happens? Like, again, the heuristic is we seek to deal with unnecessary renders, right? And the heuristic being like, as high as you need and as low as you can get away with, right?
[00:01:34]
Like, use the intent, the reason we're supposed to use something like useRef is like, get a handle on a DOM node. Now, can you do stuff insofar that it keeps that reference across renders to persist something? Absolutely. If you are then trying to then bend it even further because you needed it up that high in the tree. Like, I would argue the complexity cost of trying to use a ref or whatever to try to save one component.
[00:02:07]
Again, especially if you measure it and it doesn't really matter, right? Like the complexity cost and the maintainability cost, you know, could end up if we remain user-focused, right? Complexity equals a higher chance of bugs, right? And the most important performing app in the world that doesn't work is worse than something that works great and, you know, even has all the things we're just complaining about.
[00:02:33]
So, it is if you need something up that high, there's, yeah, like current user. You know what that is? That's probably up real high in the tree, right? And that's okay because you know who needs current user, like almost everything, right? And so it's either very high in the tree, or it's in some of the context API or like all of your favorite state management libraries, right? Like, I, you know, I'm partial to, I still like Redux.
[00:03:05]
I know that's very, like, it's affecting my hipster credibility, but, you know, whatever, or Zustand, is that how you say it, or Zustand, like they're getting harder to pronounce. Like they're all effectively using like these tools. If you pull any one of those open, you will see, like, useMemos and useCallbacks and React.memo and context APIs, right? They're not using anything you don't have as well.
[00:03:28]
So they are the reason we're kind of mostly staying with the fundamentals rather than like grabbing a particular library because it all applies. That said, there are certain things that you do need up very high. The interesting thing about the current user example is that it has two unique properties that I think are worth talking about together. One, it needs to be up high because like I said, lots and lots of things need current user.
[00:03:56]
And if it's not current user in your app, it's something else, right? It could be theme. That's another classic one. That said, you know what doesn't change all that much during the lifetime of the application? Current user, or honestly theme, you know, and so like. Yeah, it's up high in the state tree, and yeah, when it changes, it causes everything to re-render, but one, it almost never changes.
[00:04:27]
And two, when it does, probably everything needs to change. You know what I mean? All right. And so like, we seek to stop unnecessary renders, right? Not renders, because all of a sudden you start playing with useRef and you're maintaining the like, you know, in memory hooked to it across renders. You don't know what Pandora's box you are opening. Maybe nothing. But like, again, the most insidious bugs I have ever dealt with are things that like, the worst is when it was me.
[00:05:03]
But even I'm now like I have the empathy necessary of a much older developer. Where that was a good idea at the time and I saw what you were thinking and then a series of things happened after the fact, right, that led this to be deeply, deeply problematic. Side note, now that this is important for this conversation, I have also seen some of the most cursed ideas that I'm like, this is the worst idea I've ever heard, never have a single bug ever.
[00:05:36]
So, you know what, like life's weird. We measure, we deal with it, but there are no, the only laws is that doing stuff is slower than not doing stuff. But like, you do what you need to do. Like not doing stuff you're supposed to do is worse for different reasons. Okay. Speaking of contrived examples, this example is one, yes, contrived, two, the real goal is one, to make sure everyone's repos worked, and two, to make sure we all have the tools installed and we get a sense for them, and we're firing them up.
[00:06:12]
The solution, the medicine for this problem, not that hard. However, I am willing to bet money that if you go into your app, yes, it will not be an application. I'm aware of that. Right? You go in and you start clicking on your own app, you will find something that is flashing a lot more stuff than it ought to be. You will find a version of this problem somewhere, right? And it is the quickest and easiest win, because also like, you know, if it is something where you are, you know, threading that state all the way through, right?
[00:06:43]
It's also complex, you know what I mean? It's an easy win that you can use these tools to go find your codebase. I thought about skipping this exercise and I decided the right thing to do is not to skip it. So here we are. Okay, so changing anything renders almost everything. You know, even like the colors and you're like, why doesn't that change because it's actually just a div and stuff along those lines.
[00:07:11]
But changing one thing changes almost everything. Again, our job is to then also kind of use some of these tools to just see, we have a counter, cool, cool, cool. As you can see, everything like changes as we kind of go through, right? And clearly this is back when I tried to have multiple versions of the same thing, so I called these ones wrong, but like we'll probably change it in place. Cool, cool, so you can see why the unchanged prop handle, and some of these we don't, you might be like, I should use a useMemo or useCallback.
[00:07:42]
Think that in your head, we will get there. Some of these we have not totally talked about all the tools for, but that's totally fine. The medicine for this one, I like also what caused the update, like if we go down here, like what component caused it. You can usually like, I saw it for a second there and then I start clicking around, but we can usually see whose fault it is, and if it's a high enough level component, it's a good chance to go check it out.
[00:08:16]
But anytime you see stuff that is not supposed to change, it's at least the time to look at it again, like, let's be very honest with ourselves, right? Like, at this moment, right, this is coming in at 5.4 milliseconds, right? Again, like with everything running. But like, this is the world's tiniest, dumbest app, right? And this is what I was trying to talk about before, it's like, is it like, I need to solve this tomorrow?
[00:08:41]
You don't. You don't. But what happens is like you get enough of these and then one triggers the next one, right? And the tools for fixing it and triaging it are the same for the little one as it is for a few of them that are piling up on each other, right? So worth kind of seeing in these isolation, but definitely like, you know, is this a stop everything you're doing? Probably not. But let's, you know, the antidote is also very easy as well.
[00:09:15]
So I will go into here to this local state one, and we can see that, I mean, I did call it out a little bit here, that we are storing all of the state that we need up here. And so everything is going back up to application, which then changes the state that then cascades down to everything, right? So, the easiest, most effective, lowest risk, right, both for your sanity, that you could, that maybe you didn't even like, you see this code all the time, you're kind of dead inside.
[00:09:45]
It's always been in there. Like whoever came before you must have been smarter than you. Then you get blamed and it was actually six months ago, you, who's definitely not smarter than you, right? And so then the goal is obviously to try our best to push the state down, right? And like, you know, I can do all three. I will probably do one because watching me do it three times seems boring to me, and thereby I'm going to guess slightly boring to you.
[00:10:28]
And so we can grab all of these and like careful watchers will also know that there are probably ways that this too can be optimized. Don't worry, we've got more time together. We can grab these, we can go into our counter component that will not need honestly, any props. I should have, I realized that having two of every component was stupid, so we can put these up here. Cool, cool, cool. And so we'll say we got on anchorman.
[00:11:05]
What are my issues here? I would work or duplicating props, which we don't want to anymore. And I will say that it is not a bad sign if the root level component is just a series of components that don't take any props, right? Like, now, again, exceptions, current user, all those things, like absolutely, right? There's a time and a place for each of those. Oh yeah, because I'm just going to call this onIncrement because that's what it's called down below.
[00:11:41]
I can do that all here. Is it onReset? Is it onReset, onReset, I could have guessed. Right. All right, everything is no longer red, and now you can see that when I update this, we get something much more reasonable in this case. There are ways to further optimize this, right? Like, why are those buttons re-rendering, right? I will spoil some of this because it's actually a segue into the next bit, which is JavaScript.
[00:12:17]
Right? You know, we always remember the like, we've, if you've watched the complete introduction to React or whatever, you have probably gotten a lecture on how referential state, how equality works in JavaScript, right? Like two strings of the word guitar are equal to each other, but two objects with the same props and values are not because they're different objects in memory. And so what happens here is, cool, we have count, and we have setCount.
[00:12:59]
But then we are literally on every render defining brand new functions, right? They do the same thing as what happened last render, right? But we are defining these functions over and over and over and over again, right? And we have a problem here where we kind of have to. Right? Because we can't pull them out because they rely on at least setCount. I'm going to show you a trick to at least solve some of that in a second.
[00:13:26]
Right? So they have to be in here, but they also get defined over and over and over again, which means they're brand new, which means even if you say like, hey, if your props don't change, don't re-render me, guess what? They're going to re-render because these are brand new objects every time. Right? And so we will need some kind of way to say, hey, if you could just hold on to the previous one, that would be super cool.
[00:13:53]
And then we don't have to make a new one every time, because what is faster than making a new one every time? Maybe not making a new one every time, unless the act of checking to see if you made a new one every time takes more than making it, which honestly for these could possibly be the case. But if you were then threading them through a, you know what I mean? Like, this is why we started with the measurement tools, right?
[00:14:28]
In a real app, check, right? And it's like checking is not that hard. Open up tool, do thing, look, right before you just start blindly applying things you heard me say. But we do need some strategies for beginning to figure out how to keep stuff the same that should be the same, right? But I will say this one more time because it is unglamorous and you're kind of like whatever, but the just pushing state down to where it's needed is the easiest and best and lowest risk win that you can get.
Learn Straight from the Experts Who Shape the Modern Web
- 250+In-depth Courses
- Industry Leading Experts
- 24Learning Paths
- Live Interactive Workshops