React Performance

Find a Performance Issue Exercise

Steve Kinney

Steve Kinney

React Performance

Check out a free preview of the full React Performance course

The "Find a Performance Issue Exercise" Lesson is part of the full, React Performance course featured in this preview video. Here's what you'd learn in this lesson:

Students are instructed to look through the provided repository and find where the performance error occurs. Steve then discusses what is causing the performance error and provides options to improve the application's performance.


Transcript from the "Find a Performance Issue Exercise" Lesson

>> I have hidden something. We're gonna do this app three times this. Yeah, this is round one, there's three rounds. I keep moving the problem around, right? If you grab main, you won't find an issue cuz there's nothing hidden in main. But if you grab the initial slowdown exercise, I've hidden a performance issue that you need to find.

The game itself is terrible. The game itself is, Mark and I were joking about hex codes that make words and there was a website. And so I grab that and then this basically picks a random color, a completely random color of I guess 16 to the sixth colors.

And by staring at the color, you have to guess what the hex code is. You're not going to win the game, don't play the game, right? This was me when I should have been doing more important things during my day, thinking this would be a fun thing to start making that I realized I should not be doing this my time.

And I stopped, I put the performance problem in and I moved on with my life. But there is a performance problem that should, and you enthrall your computer if it's like yeah, it's still fasten you have a great computer. But typing that in Input field should be painful.

And so spend a little bit of time, and we'll just talk about what's happening. And I'm gonna add it to other places on you later. So it'll be fun. All right, we are doing this. So it's actually not hiding that component, there will be stuff hiding that component later.

This one is actually hidden in plain sight. Did anyone find it? I just found it.
>> I think it has to deal with generate random color.
>> Yes, it does have to do with generate random color, right? The trick is, I guess there's two things. So find where I put the same thing that slows us down, right?

That's one, and then how do we deal with it is I think the second challenge. So it is hiding in generate random color and I have produced many a performance issue in my day. This is like I was working on something at work to where it's we had to put something into an error state, right?

When you're trying to intentionally create performance issues is a lot harder. But where's it hiding, they will always be, why just block the main thread for a hot minute, right? But then the question is why, yeah?
>> I think it has to do with that it's an arrow function, and I think when it causes the render to application, it changes the identity in the use stages.

This is not was there before that and recalls it. Most importantly it doesn't just record once judging from the profiler, close it twice.
>> So everything will roughly, if you look at the console for those things will happen twice. Yeah, that is the right thread and it's even a little bit simpler than that which is, is it a react issue or is JavaScript just being JavaScript, right?

Which is okay, it goes, it parses this first line, right? And it's like JavaScript still evaluates all the code, right? And says yo, generate random number. And so it does and it passes under U state, and even this case reactions, like I already have the correct answer that I'm holding on to between the keystrokes.

Cuz obviously we don't wanna have it handy new one in, right? If the answer change and the color change whatever keystroke, this will leave you in a worse game than it already is, right? The issue is that as the parser and the compiler is reading through all this stuff is like, I gotta go through the the return value of this function is, right?

And a little thing like that can be what slows up the works, right? So in this case, it turns out that in the same way, the SEC correct answer you might have seen you can do. And you can give it a value, right? Yeah. But in the same way the setter also, [INAUDIBLE] that's fine.

Can take a function which is previous value. I'm not gonna hit this code. And then does something to it to get to what it should set it to. You can set, you stay with a value, or you can give it a function that it should call the first time.

So by taking this and wrapping it in an anonymous function, right? It doesn't immediately get executed by JavaScript, right? The same way if I have made this mistake this week, where you're writing code, you're writing code, you're writing code. You put it on change handler, you just pass in the function and that you that eventually should be called in there, and it executes immediately, which then it's like a set count or a set whatever you have.

And now you've spun yourself into an infinite loop before react cuts you off after a 1001 reminders. That's why we put event handlers in anonymous functions, right? It's that aren't immediately called so that we can pass this in, it will call it the first time and then set it.

And now JavaScript is good to see an anonymous function pass by and it won't immediately execute it, and thereby your slow code path is not triggered.
>> Does calling state dispatch within the main render function logic have any performance problems? The one in application jsx is being set with a boolean.

So it won't run into pass by reference issues, but are there any other considerations we should worry about?
>> So the question was basically, so we have it with this one, but what if these are all primitives, right? And so they are value equality. Even if we had an object, it is taking it the first time, that's why I said before where like react uses fibers to kind of keep track of the kind of a history line of a hook, it's not looking for that value anymore.

It has it stored whatever you set it to through other interactions. So even it's not doing an equality check on future runthroughs of this component, but the problem was this code was executing before it even got in to react, right? JavaScript itself, the JavaScript compiler was stepping in, running, generate random color, producing a random color, which was expensive, and then handing it to U state to be ignored, Mark.

>> Could you please step back and show how we can see this performance issue first?
>> Yeah.
>> Because it feels like we're fixing a problem that we haven't measured.
>> Absolutely, I mean, one of the best ways I fix it already, hold on. Can't measure the fixed one, we got to go in.

>> And also, bump the block for a little bit to make it even more obvious.
>> We're gonna bump or throttle, yeah, both I think are options. Let's throttle, let's use the tools, right? Rather than increase the fake thing, let's use the real tools in this case. All right, so go into performance, right?

We've got a bunch of different ways we can handle this, right? So we can go ahead and start by looking at the profiler, right? But like I said, one of the heuristics, I think for me, one of the places where I immediately know that I have a problem is the one place.

I think what Google has, I think it's rail, and it's like there's a set of heuristics for how you actually think about performance, and one of the ones is response time. The moment you are interacting with any way, and it is feeling slow, is a time to start looking, right?

And so in this case we could theoretically, And I'm even typing, I took forever to, So you can see as they're coming in, we're taking 304 milliseconds to render, right? And so when you have a chart that even in and of itself is showing every keystroke, we've got these incredibly long 300 milliseconds.

You're aiming for 16, right? Now granted, yes, this is a purposely slow find the react quirk that made this happen, or in this case a JavaScript quirk that react didn't need or want. But we can kind of see it in the tools. And then the other great way to do this, is you can actually see that I got a little heads up over here as well.

That's cuz I have a CPU throttling, let's see. The other way that I will very frequently do this, and again this kind of goes to Alex's question, of which set of tools do you use? Scroll down, is a really great way is Chromium, right? So depending on which browser, will flag anything that it thinks is problematic, literally with a red flag, right?

And so if you run a profiler, and you see anything with this little red thing, it's hey, that took way too long, right? And I'm just gonna tell you now, there are things that you didn't think were bad that it still feels as bad, and it will hurt your feelings.

So be aware of that, right? But we got a 300 millisecond lag in application rendering. So we can tell it's pretty high up there. If application was this big, wide bar, but underneath it, there was another equally wide bar, which when we find the bug, not to spoil it for you, you will see.

But that kind of shows you the depth of that flame graph and how wide. It shows you how deep in the component hierarchy it is. The other thing is you can see that we are peeking. And again, this is intentionally blocking the main thread, right? But you can see we get flags here, and as I said before, you wouldn't see this in production.

Application, and then generate random color, right? Those wouldn't have their names in the production build. It is the providing of all that information, which again, doing stuff is slower than not doing stuff. So in production, it does not do these things technically. Unless again, you work on a developer tool.

A lot of times your customers are not the ones debugging and triaging your performance issues for you, right? So you don't provide them all that stuff because it slows it down. But for us, we can actually see what function was the one kind of calling it in this sense, and get a sense there as well.

But yeah, the red flags and looking at that CPU graph, but then also seeing which component it is. And as we play the game a little bit more, we'll see it a little bit more if it's hiding down a level. You'll see where the wide part of the flame graph was.

You can kind of get a sense of what is, this one was literally the second line of the root thing. So it is a long and sad, but relatively simple graph.
>> You had mentioned 60 milliseconds. Is that like a heuristic we're trying to head?
>> Yeah, that's a heuristic.

>> Okay.
>> Yeah, I think the heuristic is refresh rate of 60 frames a second, a second divided by 60 16.66666, and so on, so forth, right? And so beating that doesn't really do any good cuz yeah, the screen refreshes 120. That is why the heuristic exists. It depends like most things, right?

I work at a company that also needs to make money, and me getting it from 20 to 16 is not always gonna get me adulation, right? And so there is what is what we should aim for and then what is practical. So we continue getting a paycheck as well.

>> Kind of along those same lines, a number that I circulate with Adam, cuz he works on one of the teams that I work with, is generally speaking, humans can't perceive anything less than 50 milliseconds. So If you have a single render cycle that takes 50 milliseconds, you're probably okay.

But it definitely adds up if you get in that render loop and you stack them up.
>> I forget what the threshold for the Chrome tools yelling at me is, I know that 300 obviously passed it. But I don't remember off the top of my head what it is, Mark.

>> Maybe you're gonna do this, but could you fix it and then let's see it again?
>> And Alex, why didn't you ask me a question while I fix it?
>> Yeah, so I think this was a great example when we actually need to combine the React profiler, and it looks like when the issue is with the GS itself.

This [INAUDIBLE] because the the React profiler wasn't particularly specific in terms of where-
>> Exactly, showed you what component it was in, but it didn't show you in the same way that this did, right? All the fixing rerenders in the world is not gonna save if you from your slow, just regular JavaScript, right?

But yeah, using them together will then help, at least you find as a concerted effort. Let's do this one first, let's go in here. So I added the anonymous function. All right, and now you can see, I don't have those long peaks, right? The probably initial R render still somewhat unhappy with, cuz it does call generate random number ones, right?

That function is still slow, right? So I do get yelled at over there, but you can see that subsequent rerenders are not calling the issue in this case. And let's do it, let's pull up the, As well. All right, in this case now we're at 2.1 milliseconds, right?

And we are probably the only time that those are probably in existence, but probably so tiny in comparison. They can make a bigger appearance in a 2.1 millisecond line than they can in a 300 millisecond line. But yeah, are there as well. I get these are kind of, you can see game input was changed at this point.

You can see what changed each time. Expensive component is not expensive yet. It will be, and you can guess where I'm moving the problem next. But next you don't get to just like figure out where it is. You got to do something with the component, and so it's like I can name it a little bit more obvious next time.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now