How to use the new experimental Profiler feature in React

Published on November 07, 2018

How to use the new experimental Profiler feature in React

https://medium.com/@dave_lunny/how-to-use-reacts-experimental-new-profiler-feature-c340674e5d0e
  • Transfer
Here comes React 16.4.0! (Approx. Translator - this feature was added in version 16.4.0, then this post was written). And at such times you realize how JavaScript you are - a geek, if you follow the minor updates of your favorite framework. Fine!



If you read the release notes for version 16.4 published by the React team, you should find this update quite boring. Pointer Events look tempting, but to be honest, before that I heard little about them.

In addition, there is a bugfix for something like a new method getDerivedStateFromProps(now it will be called at each render). I have not used it enough yet, so for me this update was not very important.

Then I saw the announcement buried under the headlines that they had added a new experimental component unstable_Profiler. Seeing that my life is now quite unstable ( unstable_), I decided to read the RFC and try it.

TLDR;


People from the React team are trying to render asynchronous . This can make it difficult to determine when components should be rendered during mount / upgrade. Therefore, they are messing around with this new shiny component. Profiler

So what can you use today?

So, if you are a pro in monitoring the performance of your reactive applications, this will definitely be another good tool in your arsenal. If this is not about you, you can no longer read and go back to creating cool applications.

Using <profiler />


Warning : maybe you should not use it in production (well, in fact, it’s the same unstable_). Later they will finish the ability to profile and production code.

In principle,Profilerthis is a component that can be extracted from the React package by default. Since he has a cautious underscore name that many linters swear at, you can get around this as follows:

import React, { unstable_Profiler as Profiler } from 'react';
...
const Profiler = React.unstable_Profiler;

Now that you have it Profiler, let's take a look at the components! You can wrap any part of your JSX tree in Profilerto see what happens to it. Profiler accepts function onRenderin which data on time of drawing are fixed. Here is a simple counter example :

import React, { unstable_Profiler as Profiler } from 'react';
class ComponentWithProfiling extends React.Component {
    state = {
        count: 0
    };
    logProfile = (id, phase, actualTime, baseTime, startTime, commitTime) => {
        console.log(`${id}'s ${phase} phase:`);
        console.log(`Actual time: ${actualTime}`);
        console.log(`Base time: ${baseTime}`);
        console.log(`Start time: ${startTime}`);
        console.log(`Commit time: ${commitTime}`);
    };
    go = direction => () => this.setState(({ count }) => ({
        count: direction === "up" ? count + 1 : count - 1
    }));
render() {
        return (
            <Profiler id="app" onRender={this.logProfile}>
                <button onClick={this.go("up")}></button>
                <div>The count is {this.state.count}</div>
                <button onClick={this.go("down")}></button>
            </Profiler>
        );
    }
}

Consider that you have to give ideach piece that you profile. As you can see below, it onRendertakes a bunch of interesting metrics:


7jroojkv30.codesandbox.io

First, you can see what the rendering phase was ( mountor update), which can be used to identify parts of the code that unexpectedly updated (just like a great why-did-you-update package , which I used many times and highly recommend).

Next, we get actualTimeandbaseTime. They are related to the actual time React spends on rendering calculations; those. finding out what has changed. Note that the actual time (actual time) of the initial connection (mount) is longer, the update time (update). This is because at the initial connection technically everything is “new”. While updating, calculations should be simpler, because, I hope, the components in the tree are updated only if they really changed (that is, when the values ​​of prop / states changed).

In large / real-world applications, this data will allow us to understand whereshouldComponentUpdateis used incorrectly or not used at all, places where props with reference types often change or transmit new props, or just places where you didn’t expect updates to take so long.

The last values ​​we get in onRenderis startTimeand commitTime. This is, in fact, timestamps since the initial launch. startTime- this is the time from which the selected component began to perform calculations for drawing, whereas commitTime- the time when React actually recorded these changes when drawing.

If you are tracking other events with time stamps (such as clicks or keystrokes), then these metrics can help identify the deltas between when user events occur and when actual drawing occurs. If the gap is large, this delay can be noticeable to users and should be carefully examined.

Conclusion


For me personally, this tool will not be very useful yet. But this is one of those things that are good to know about, because if I ever come across these performance bottlenecks, it would be a good way to measure them.

It is important to first measure your performance problems, so when you make “improvements,” you can tell if this really improves the situation or only makes it worse. I found that performance optimization is one of those things that you can spend a lot of time on. Therefore, before you optimize something, make sure that it is really necessary.

I look forward to what the React team will do with Profilerin the future. Thanks @bvaughn for adding this elegant feature!

From the translator:
At the moment (actual version 16.6.0) Profiler does not work in server-side rendering. Feature request is already there.