ReactNext 2022 www.react-next.com Israel's Annual React & React-Native conference
Powered by EventHandler ----------------------------------------- Profiling React Apps like a Pro: As front-end developers, we strive to build fast and fluid web apps. But how can you profile your React app and find performance problems?
In this practical session, we will deep dive into a profiling session to understand how to use your DevTools to solve performance issues.
----------------------------------------- Gil Fink: Gil Fink is a web development expert, Web Technologies GDE, Microsoft Development Technologies MVP and sparXys CEO. He is currently consulting for various enterprises and companies, where he helps to develop web based solutions. He is also co-author of several Microsoft Official Courses (MOCs) and training kits and co-author of "Pro Single Page Application Development" book (Apress).
Hello, everybody. How are you? Having fun? Yes. How was lunch today? The vigil ate. Vegan? Vegetarian. Okay, cool. So I'm very happy to be here, and I am very happy to be with you here. And I want to start with something that probably it's. Hypothetical thing never happened to you. You're sitting in the office working on your website. You're adding features to your website on your machine, which is a main developer machine, never happened to you. And on your machine, your app is such a great app. It runs fast, everything is fluid, and you are very happy with that. And then you ship it to production, very happy. And hopefully you're hoping that your users will love your app as you do now. Meet Mark is your user and he's browse into your app and he's like waiting and waiting, really. And then he navigates from one page to another and everything is like junkie. Or he tries to do interaction with the component he created, which is very cool. But on his machine or his phone, nothing works as expected. And Mark, as you might think, really loves those very fast and fluid applications. And all you did is just try and it worked on your machine. But performance training is very hard. It's not something that we take care of when we are developing. You are running and you are writing your application and you are developing your application on your main machines at your office, but you're not doing any performance profiling or any performance tuning during the development phase. And this is me saying to you, please add 2 hours, 3 hours into every sprint in your application building dedicated for performance tuning. And this brings me to this talk, because we want to make Mark happy. We want very good performance applications. And as I said, we will learn how to profile our applications. And hopefully by the end of this talk, I will try to convince you that you need to add to your sprints, few couple of hours every sprint to performance profiling and performance tuning. A little bit about myself. Karen said that I'm Gilphink. Yes. I'm Gill Fink. I'm the CEO and a senior consultant in Sparks. Sparks is my own company. We have only one employee me, myself and I. I'm both a Google Developer expert gde and the Microsoft most valuable Professional. Which is MVP. These are awards. This is not a test that you're doing. These awards were given me by these big companies. I wrote in the past a book called Pro single page application Development. That book was written with back Pong. Yes, sorry. It's not React, but it was written in 20 13 20 14 when React was in its diapers. Okay, so still the concepts there are relevant for today, but who uses it today? Maybe for a paper in your bathroom. What we're going to do in the next couple of minutes, I'm going to talk about what we are going to measure. Then after I set the ground, we'll talk about the profiling process. And in the end, we'll see a few scenarios in React that will give you hints of what we are searching and how to search those things. So, as I said, what we are measuring, who knows what is core Web Vitals? Raise your hand. Okay, not a lot of you. So this is something that Google produced a couple of years ago. These measurements are part of Google crawler. They are measuring everything about your application. And when you are running paid speed or lighthouse and things like that, you will get scores. The scores are according to these web Vitals. So let's talk about a little bit about what are those web vitals? LCP acronym for Largest Content Full Paint. This means how fast your app is loading. Okay? And the measurement below 2.5 seconds is a good measurement. If you are hitting the 2.5 to 4 seconds, then it needs a little bit attention. Up more than 4 seconds, run to your office and start refactoring your application because it's not good feed FID. First input delay interactivity. When you are using event handlers, when or how fast is your function working? Okay. Okay, I pressed a click button. I'm going to the server. I'm doing something returns. I'm rendering the component. And how much time will it take? If it takes below 100 milliseconds, it's good. Between 103 hundred milliseconds, you have something to improve. More than that, run to your office and please refactor your component. CLS cumulative layout shift. This measurement checks the visualization stability. What I mean by that, you have animations. Each animation or each frame that you produce to the screen must be below ten milliseconds. If it's not below ten milliseconds, you will drop a frame. Okay. And this means that your animation or your interactivity will be less performant. Okay, now that we understand what we are measuring, let's talk about our tools of trade. First of all, the React profiler. We are in a React conference where we might work with React profiler. This is one tool that I'm going to present today. The second one is a new tool that Google added to the dev tools, which is called Performance Insight. Very cool feature. It's very helpful to get insights about the performance of the interactions that you are creating. And the last is the oldest, which is the performance tab. Okay, we will see all of these different developer tools in action later on. Now, how you read the performance data. In order to read the performance data, you need to understand what React is doing underneath its engine. Okay, first of all, when something changes, react runs the render phase. In the render phase, what React is going to do is calculate the diff between the current virtual Dom and the new virtual Dom. And then React gets into another phase, which is the commit phase. And you will see in the profilers only the commit phase. In the commit phase, React updates the Dom itself with the changes that you created. Okay? It's the lifecycle hooks in the class react components or the use effect and et cetera. Okay? All the changes will happen. So when we are talking about the profiler, we are talking about commits, we are not talking about the render phase. So with that in mind, let's jump into our first demo. So we have an application and our manager says to us something is wrong with this application. Please check the performance of it because users are complaining. So what we are going to do is of course open the developer tools. The first tool that I'm going to show you is the new Performance Insights. This is an experimental feature in the dev tools but you can try it out today. Okay? So let's measure page load and let's see what the Insights are telling us. There are a lot of things that we can see here. What I'm going to show you is the inside tab. Okay? And in the inside tab we have a long task after Dom content loaded. What is this long task? You can see here that there is something called Slow that is slowing our loading. What is this slow. Okay, let's jump into our application. And in the application what you can see here is this is a component called Slow. Okay? The Insight told us that it is running very unperformant and this is because we're doing a lot of calculations here. Now sometimes when you are looking at things like that, it's the page load. It's not hurting us a lot. And maybe I can't tweak this algorithm to do anything to make it much faster. But let's talk about another thing and let's jump into the React profiler and let's do some stuff in the page right now and let's check things out. Okay, so I'm recording and I'm going to do something like let's press search and let's press something else and let's stop the profiling. Okay? Thing to notice here, first of all, what's, what we see in the profiler is that I got two clicks and two frames. And in each and every frame slow is always very slow. And the clicks weren't part of the slow component, okay? They were part of this component here, which is called Search. Okay? And here is the search component and it is not relevant to Slow. But slow is making this component or the re rendering itself, making everything else here non performing. So what can we do? How can we solve that? We can't change the algorithm, but this algorithm affects our rendering. Somebody said use Memo. Okay, good. So let's use Memo. React use Memo is one thing that you can do in order to memorize the output of some function execution, if you are familiar with that. So once I used react, use memo. Now what we are going to do is I'm going to run this code again. Okay. I'm going to validate that frames aren't rerendered. Again, didn't run the profiler. Voila, slow, wasn't rerendered. The only rendering that we had here is the search. And we have only one frame, even though I clicked twice. Okay, so this is one thing that is very relevant to our application development. We understand that we have a problem. We try to solve that problem, and we have some process to solve the problem. But I didn't say anything about process. I did something with you together. So let's talk about the process. Okay, you haven't seen, but what I've done is a process that is called profiling. In the process, what we are going to do is the following things. First of all, establish baseline. What is established baseline. This phase I didn't do with you, but in most cases, you're going to run in incognito mode in order not to be affected with extensions from your browser. Also, you will put a label on the code right now or create a new branch, call it profiling or anything else. This is the baseline of the profiling process. Then I use the profiler to collect data. Okay, we're collecting the data. Once we have the data in hand, we're going to analyze the results. We saw analysis of the results in the performance inside. This is something that Google did to us and in the React profiler, this is something that we had to analyze together. Once I analyzed it, I'm trying to figure out, like a CSI detective, crime scene investigator detective, what might affect the rendering of the things that I did. And then I try to solve it. I tried to tune up the application in order to see whether the things that I did works. Once I did that, if you remember, I did the test and measure phase. What is the test and measure phase? I'm testing again the application. I'm seeing if the changes that I did affected the performance. Yes or no. If no, then I reject those changes, and I'm starting the cycle again. Collect data, analyze result, tune up, and test and measure. Once I see that I did manage to produce something better in performance manner, then I'm pushing that branch into the main branch, and I'm supposed to be happy. Okay, so this is the process. Now, until the end of this session, we are going to see a few scenarios in React, and we will do the profiling together. Okay? So in the application here, I'm going to move to the movies tab. Let's do that. And in the movies tab, we have a lot of movies that I like, star wars fan. And what I'm going to say is there is a problem in this web page, and I'm going to try to figure out what is the problem by, let's say, change title. Change title. Change title. And voila. We have a problem here. Let's talk about the problem. Okay, so, as I said, first of all, we collect the data. We're in the profiler right now. And in the profiler, I press the button three times. I get three frames. But in all the frames, there are a lot of rendering here of the movie component. Okay? This is legal optic because it's very fast. But think about a very big data source that you might have, and you have rerendering of all those movies again and again and again, but they are rerendered even though I pressed this button, which in the application right now. Let's take a look at that application again. This is the movies and this is the Change title. And we have a map that maps to a lot of movie components. How will you solve the rerendering of all the movies which are only presenting data, but nothing changed in them when I click the Change title button. React Memo. Thank you very much. Okay, so let's use it. Let's use React Memo. Okay? Now let's talk a little bit about React Memo and why it is different from Use Memo, which we saw earlier. Okay, so React memoir is a different beast in your toolset. It's not Use Memo. Use Memo works on function and memorize the output of a function. React Memo, memorize the React component output or rendering. And if nothing changed in the props, it won't rerender. Okay? So thank you for saying react. Memo. Let's see it in action. Test and measure. Let's see if it works. Now let's rerun this web page again and let's profile everything again. Okay, so let's clear the previous profiling. Let's change the title. Change the title. Change the title and let's stop the profiling. And what you can see here is that all the movie elements or components didn't rerender. Now let's move to a different scenario. Let's move to this scenario, which is colors, okay? And I will give you all the demos and you will be able to play with them later on after the talk. So you will find it in my Twitter account. I will announce the demos. In this example, I want to do a few things. First of all, to show you the performance tab. Okay? The performance tab gives you the ability to look at the performance of your web page both in loading and in some scenarios. So let's check what's happening here. In this webpage, I'm recording the loading of the page again, and once it is produced, I can assure you that there is a performance problem here. Then let's talk about that performance problem. Okay, so I can make it go higher than that. I can do that, sorry. Let's open it higher and I get the timeline of everything that happened during the loading. Okay, one of the things that you might see is that we have 300 milliseconds of scripting. Let's go to bottom up and what you can see here is 40% of the time was spent on decimal to x. Decimal to x is probably a function that is called very often. Okay? And I can jump into the color component and say the function here, here is decimal to hex. And this is how this application renders all those circles. We have some use effect and we set the background color of the current circle. Okay, we saw a lot of circles there. Do the decimal to x on red and green and blue and things like that. Okay? Because we got all the red, green and blue props to the component. So you can think about a way to go around this problem. It comes from CSS. Okay, we are setting the background. We're doing a lot of calculation with decimal to hex. We can remove the decimal to hex because in CSS you have RGB function. This is the CSI way of thinking. Okay, let's see it in action in the color component. Instead of doing decimal to x, what about us doing the following, okay? Instead of this, don't run decimal to x, run RGB with the red, green and blue that you got. Might it solve the problem? The bad performance that we saw here? Let's see it. Let's clear this thing here. Let's rerun this entire profiling again and you will see that in test and measure the graph, the timeline got thinner or thicker. And we don't have decimal two hex pointed out in our bottom up menu. This is because it's not being called. We are calling different ways, different things. And we got a performance boost because we're using something else than the things that we're regular to use. Let's jump into the last example that I have for today, which is abuse use state. Just do something like this. I'm trying to move my mouse which is in a very thin slot and this is very hard. Okay, so what we have here is another demo of those colors. And instead of doing something here, I'm just checking whether I'm getting long press or some click. Okay, how do I do that? Let's move again to the profiler and let's profile everything here. Okay, so here we have long press remove. Long press remove. Let's stop profiling. Now we got a lot of frames here. You can see here that I clicked the things here twice. Okay? But I got a lot of frames working or a lot of rerenders, a lot of commits that React did. And whenever you see a lot of frames produced in the graph here in the flame chart, that might indicate that you have a problem. Most of the problems here might be solved by use callback and things like that. But sometimes it's just because you are abusing your state. Okay, so let's take a look at what is happening in my component right now. And inside this thing here, the color here, you can see that I'm using React memo I have a reference, I have some is longpress, which is one state that I'm checking whether I'm currently in long press or not. I have an action which is click or long press and et cetera. Now I have a set timer that I'm setting with the set timeout here. And I'm changing the long press to true set action to long press. Whenever I release the pressing, I'm clearing the timeout. I'm doing set timer to undefined, then set is long press to false. What is wrong with this code? It is working. It is wrong because whenever you do set is long press here and here, you're trying to change something which isn't relevant to rendering. Okay? I'm abusing the state. It's not relevant to state. It's relevant to me to indicate something in my component. Okay, so how can we resolve that? Use ref. Thank you very much. Use ref timer instead of this timer and set timeout. And I can change the code here to something like this. Okay? Clear timeout and timer. Ref current equals undefined. And of course, I will have to also change this code to set timeout handle, get into the timerref current, and voila. This is how I'm solving this problem. And if I will check the profiler again, you will see less frames produced. Okay? Whenever you're using ref, it is not affecting the rerendering or it's not producing another rerender. So this might be a hint or tip to avoid use state in some things. And I can assure you that this code was in production in one application that I helped to build, and I didn't write this code. Okay? So with that, let's summarize what we saw here and let's move on to the next session. So performance problems will happen. It is going to happen to you. But if you're adding performance tuning sessions during your sprints and you are checking that you are performance or producing good performance during the development cycles, then your users might not complain. Don't wait. The users complaints about your performance make Mark happy. Thank you.