About this talk
This talk covers the issue of wasted re-renders in React applications and how to effectively monitor and address this problem using tools like Babel. The speaker, who works at Dynatrace, highlights how half of the renders in current React applications are unnecessary, yet it's challenging to pinpoint their causes with existing profilers. By leveraging Babel, the speaker demonstrates how to inject monitoring capabilities into the production build of an application. This technique utilizes an abstract syntax tree (AST) to wrap hooks and gather data on performance. The speaker emphasizes the importance of understanding the exact causes of performance issues rather than relying solely on quick fixes like React memo.
Full transcript
Ready? You ready, right? So, okay, we have some time. So, let's introduce each other. My name is Andrey and I'm so geek that I connected the Xbox controller to the whole presentation. So, let's check it if it's working. Great. Then, 3 2 1 go. So, I'm working for Dynatrace and in Dynatrace we're monitoring everything. We're working with observability. my today talk will will be about uh killing
wasted re-renders in the production hook. How happened that I get into this one? actually, I'm so curious that I'm testing everything and I have uh professional damage, as you can see. I monitor everything. Even my whole presentation is monitored. When I asked at my colleagues, what I actually uh should I show to you today, they said, "Show them this slide and go away." Actually, everybody should know
this. So, technically, about half of the renders that we're having in the React currently is wasted. So, we don't need them. And the problem is that nobody knows why it's happening. So, I decided to make it more dramatically. Act first. And let's speak about the problem. So, what we have? We have a lot of tools to monitor React and React applications like profiler and we also can
connect to anything that we're having on the market right now, including Dynatrace or Sentry. There's I I've seen them. So, actually, it's possible. But, what questions are all this monitoring on all this information is given to you. So, okay. We have profiler and it's wrapping everything around the any component and it shows you when it loaded, how is it loaded. But, let's take a look at the
right part that I have. We do not know if we have a hook, which hook was run, which dependency used, which function was used, and this information we cannot get from anywhere except manually injected. So, what I can give it to you. So, this is the information that I get from the profiler. So, nothing. Amount of renders, updates, the milliseconds, and let's land in another problem. I
brought the demo. Mhm. So, for the demo, I took abstracted flow that could be shown in any applications like NNN or a lang dog, whatever. what can we see here? Let's just touch something. And here is the problem. As you can see, no numbers are changed and it's not the broken application. The problem is if we go to the development, we will see all the numbers. Profilers
is working. Renders are working, but it's localhost. This is not the localhost. This is the production build and in the production build, we don't have any numbers. What can we do here? We here can inject everything in the build stage. And in the build stage, we can use some tools like Babel, like SVC or JS code shift, for example. So, I will use Babel today because I
suppose the Babel is the most efficient way how you can do this fast and it will build application faster than uh any competitors. So, just some short theory what the Babel is doing. The Babel is injecting your production build. It's taking the production build on the on the build stage and inserting the code in the exact places where you want to have the code. How is it
happening? So, we cannot just put the code somewhere. We using the AST. It's abstract syntax tree that is exist in the TypeScript. Using this tree, we can definitely know which function we should wrap, what this function is doing, what this role of this function, and then we can just check if it's use effect, use memo, or any other hook and just wrap it. Every single The only
difference, we could do it manually, right? So, we can go into our application found find any hook, wrap it with something and then measure the data. Imagine, legacy code that half of the team do not know how to work with. It's contains 30,000 lines of code, and we need to find every single hook and wrap it. What should I do with it? So, manually it's really hard.
Okay. In my experience, I tried to use cloth like everybody just okay, take this, wrap everything. it did not manage it. He took a lot of tokens, but result was really really really bad. So, I landed that we have engineering way how to do this without AI. We can just use the Babel and ask, "Please wrap everything what we have with the monitoring." how is it happening?
We technically can find the component. in my example, I simplified um how I will do this. So, I checked everything with the uppercase. So, like let's say that all the files with the uppercase or all the classes or functions with the uppercase is are the components. So, of course in the real example, it will be not like this. You will need to use your own rules for
But, in my case, I did it like this. So, it's easier for me. I tracked all the hooks inside every and then wrap every component with a that is just taking the hook, wrapping with the data, taking the component name, and providing a lot of information for me. how is it working uh for the production? So, why it's better? if I will do it manually or using
any AI tool, all the changing code will go to the production or whatever, and I will need to manage it. So, I will need to support the new code with all the wrappers. And if I will not need them anymore, I will need to go into the every single component and delete everything. with the Babel instrumentation, I can just say, "If this flag is exist in my
ENV, then wrap everything. If not, then just don't do anything. I will look the full instrumentation then if I will wrap everything with a babel. And let's go to the example. So, now I feel safe because I have a lot of data that is coming from every single hook. Which container, which node, what exactly is going on. I know everything what is going on here. every time
when I'm doing, I'm see that the dragging is going happening. I see the data. I see which services was touched. I see everything. So, now I feel safe because I know when can monitor the data. And I can say which hook created this problem for me. So, this is abstracted code. It will be an example and if anybody will need it, I will share the link. You
can go inside and take it. for the track store, I used uh the information that almost 200 milliseconds of loading the module and then we have polling. And that means that some data is wrong. So, it's not the hook. It's not the render. That means that some data is wrong. So, sometimes every time when we're changing the data, something is going on with the re-renders and we
need to catch it. we can see what the instrumentation has found. I see that every time when I'm dragging the node, I have 50 runs. I know use effect with ID. I know which dependency with ID. And I know which object is did this. So, now we can definitely catch our bad guy and punish him. Also, we can find some other information. It could be important or
not, but I just decided to add it also >> [snorts] >> So, the last act, how to fix this thing. So, as we know the performance issue was not in the rendering of the component, it was in the use effect somewhere. We need to fix it somehow. >> [sighs] >> I found the exact code, so it's in the screen. So, I found where exactly it's located. There
is a lot of notes. And I put the fix inside. So, now we have the new reference everywhere we render, so we don't have minimization there. So, I'm not used React memo, I'm not used nothing except pure JavaScript here. >> fair question will be here. Every React developer will tell me, "If you need to put something and catch something, just use a React memo and that's it,
and everything will be fixed." But, I don't want to use React memo just I want to know why I use it. So, because every time every single line of code will be inside of our application and we'll need to support it. So, it's we just can't add memos inside and say like, "This is the fix." Who told you this this is the fix? Instrumentation told me. this
is comparison. I will show you in the dynamic kit, but this is like complete comparison with the re-renders, how many effects was before I fixed it. And it was about 2,000 of re-renders and memos about 2,000, and the data is 10 times less if you find the reason and fix the reason exactly, not just putting the React memo everywhere. I used almost >> [laughter] >> half of
my time and it's almost done. So, this is the takeaways that you can take for your next Monday. The production code is not instrumented you can use the Babel everywhere, every time you want, and it will not break your production code. Identify objects is really matters. It's just not putting the caching everywhere inside the code. You need to understand what exactly is going on inside. Um compile
time is also important. It's the tooling for your next level. So, today uh I gave you some short explanation about the AST. Tomorrow it will be a bit more. Please come. >> [gasps] >> Um thank you. Thank you for listening. And if you have any questions, shoot me right now. >> [applause]