Lesson Description
The "Pushing State Down the Tree" 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 discusses pushing state down and balancing state in the application component. He walks through the code and shows how to improve state management by restructuring components. Steve also demonstrates a refactor, moving logic to the right place and highlighting practical performance trade-offs.
Transcript from the "Pushing State Down the Tree" Lesson
[00:00:00]
>> Steve Kinney: But let's, you know, like look at some of the initial ones here. Now, the obvious, and again, some of these are contrived because like making purposely bad apps is a lot harder than you think it is. Um, typing into this input field probably should not re-render like almost everything, right? Does anyone, just looking at the flashes at the very least, have a hypothesis to what the issue is? You haven't seen the code.
[00:00:29]
I'm not expecting you to know, but I'm just opening the floor for hypotheses. Yeah, uh, it's updating the context or global state. Uh, let's go with the second one because I didn't put the context API in this one just yet. Um, we can recreate, we'll solve some problems, and we'll recreate some problems. Uh, right now, it is effectively the first and foremost easiest slam dunk you can almost never go wrong with rule is the balance of, uh, pushing state down, you know, as you're keeping state as like low as you can, as high as you need it, as low as you can get away with, right?
[00:01:07]
So if I jump over to this code, you will see like the first cardinal and you're like, I would never do this. This is a, let's go into deep thoughts. I would never do this, right? Um, yeah, you would never do it in the application component. You've done it somewhere. I know that you've done it. Uh, even if like you did, it had a good reason at the time, and then things changed, and it just ended up in that state.
[00:01:31]
Like most of the worst parts of my codebase were. The code when it was written was good and everything else changed around it, right? Uh, so let's not get into shaming here. Things happen, um, which is, if we look at the application component, we can see that we have this draft thought, which is that thought that we're going to create and add to the DOM, right, in the application component. We got a lot of problems in this obviously because it's an intentionally bad app.
[00:01:59]
And then we take that draft thought and the ability to set it, and we pass it down into this captured thought. And one of the kind of interesting like conundrums that there's not necessarily a right answer to, which is like, this function now gets called, it goes to its children, right? Um, and like that's down into capture thought, which then could like call something back up. There are two options, which is to push everything, all the state down, or to flatten that component tree, right?
[00:02:41]
Sometimes it's not about like pushing the state down and memorizing stuff, it's just like, did that need to then render another component or could that have just been in line in the component? Like, the answers are, maybe it would be more performant to inline it, but you're using that component 6 other places, at which point it doesn't matter what's more performant because you need to maintain this code.
[00:03:05]
And like, honestly, the cost is not that high. Like no one saw this thing lagging as I was typing. It was just flashing a lot. Like, live with it, because the ability to maintain this codebase and have it be reliable and consistent. For almost no other than a fake app, problem is not that bad, right? Um, but if I like then I'm also like, you know, you can assume the capture thought is maybe a one-timer, right?
[00:03:32]
But if it was like button. Well, you're probably using that button in lots of places, right? And there's, you know, if it's just some CSS classes, maybe you do it like that, but maybe your button, it's also like one of those buttons they pass it in HR ref, it can also be a link bane of all of our existence, but every designer makes us do it. Um, you know, those things, there could be logic. It makes sense to pay that cost.
[00:03:58]
Don't overoptimize that, right? This is a fictitious example. Um, but we pass in draft thought so that I can put it in that input field, and then we pass in set draft thoughts so we can update that state, and then we pass in this on submit. Honestly, other than the act of adding that new thought into the array of thoughts, which has to happen up here because the like thought list and the individual thoughts need it, the act of keeping that draft state and changing that draft state doesn't need to live up here.
[00:04:33]
Push it down. Right, because the like render only goes down unless it's been given like calling stuff back up to the application. So, in the world's simplest refactor, which just felt right, they'll get harder, don't worry. Um, but it felt, it felt polite to start us off with an easy one. Um, we're going to take this logic that only is of a concern to the create thought, and we're going to put it where it belongs, right?
[00:05:03]
And so we'll see some red squigglies for a second, um, but we'll take this, we'll cut out that hook completely. Right? Um, all we really need to do to go back up is to get to that array. Right. And obviously now like TypeScript angry at me, but we'll save that for a second. I'm sure Vite's now angry with me too. Um, we'll get rid of the on change and the draft thought because now we're not passing them in anymore.
[00:05:40]
We only care when they hit the submit. And I'll show you another hack you could do a little bit later. Uh, we need to pull a new state. And then on change we'll just set that draft thought and I see no red squigglies and I see no red squigglies, so I should be good. My font is very large, if you see something I'm missing, like see something, say something, right? And hopefully what we'll see, I'm going to give it a page refresh so I don't have a false positive is the entire application is not re-rendering from honestly just a sensible refactor.
[00:06:17]
Right? But you might not even know that you have some of these, because again, the chances of you doing it intentionally are not zero. But the chances of them, you ending up with them over the course of months, years, so on and so forth. Like there's nothing been more humbling in my life than being like, get like initial commit on a repo and then having to live with it for 4 years to just see the way things get weird and how good decisions go sideways.
[00:06:45]
No one's blaming you, um, but you should like measure and deal with it. Um, so now we are only affecting. You know, and like we wouldn't even see that input necessarily if it wasn't a component in and of itself because like React doesn't have to do the whole reconciliation process with the actual DOM, right? It's only doing it for our components. That said, right, if we do the recording, I'm going to clear this, um, I'm going to clear this for a second.
[00:07:22]
I'm going to hit record. Um, hello with way too many L's, right? We can see that the entire like, um, took 1.3 milliseconds. I will remind you, the browser paints every 16.6 milliseconds. So effectively, if you can get all of your stuff in in under 16 milliseconds. It doesn't matter. Right now, obviously, if you're at like 15.7, all right, maybe think about it, right? But if you're at 1.3, stop being like, well, it's still flashing, and Steve told me if it's flashing, it's doing unnecessary work, and that's not, nobody cares, your eyes can't see that fast.
[00:08:00]
Right. No, it doesn't matter. Stop it. Right? And so like, the cost of having a reusable input component that I can use as part of my design system, instead of having to individually install every input in my app, I'm happy to make the tradeoff for an extra flash that doesn't mean anything, right? Because it would be imperceptible. Even if I shaved off a like 10 of a millisecond, imperceptible to anyone because the browser is not even going to render it, right?
[00:08:32]
So do not like measure and make sure what you're doing makes sense, right? Um, as you kind of go through. And now this entire thing is not changing. Now, to be clear, we have lots of problems here, right? Um. Like the act of like. Hitting like edit, I, you know, make stuff a little bit smaller, right? Um, OK, that only affects that one, but it's hitting a lot of stuff in here, um, forget renders everything, so on and so forth, and we're not going to get to the bottom of this particular app, but you can kind of also go explore and play around.
[00:09:04]
We're going to like also kind of try out some other ones as well, um, but you can kind of see the like methodology that you would use either one. Check on the status of that buildup that everyone will tell you, like, only me and only solve the big problems. Like, I'm going to tell you, don't be ridiculous, but also like be looking around the corner of future problems because I've worked in enough codebases that are like 5, 10 years old where no one did, and now it is an all hands on deck problem.
Learn Straight from the Experts Who Shape the Modern Web
- 250+In-depth Courses
- Industry Leading Experts
- 24Learning Paths
- Live Interactive Workshops