React Production Performance Monitoring

We want our React applications to be fast and responsive. Often times, it's only when a customer or user has complained that we learn about a potential performance issue in our production react application. This is where real user monitoring comes in.

Polaris provides real user monitoring for your react apps with real-time indicators of runtime performance and reliability.

Prerequisites

React Profiler

The first step is to use the React Profiler to measure the performance of your components.

React
import { Profiler } from 'react';

<Profiler id="app" onRender={handleOnRender}>
  <App />
</Profiler>

You can use multiple Profiler components to measure different parts of your application. However, keep in mind that each use incurs a small CPU and memory overhead.

The onRender callback will be invoked with the following signature:

React
onRender(id, phase, actualDuration, baseDuration, startTime, commitTime) {}

Let's review each of the parameters:

  • id (string) - the id prop of the Profiler tree that has just committed
  • phase (string) - either mount (if the tree just mounted) or update (if it re-rendered)
  • actualDuration (number) - time spent rendering the committed update
  • baseDuration (number) - estimated time to render the entire subtree without memoization
  • startTime (number) - when React began rendering this update
  • commitTime (number) - when React committed this update

Profiling in Production

Using the Profiler in production requires some updates to your application's build configuration.

Learn more about profiling in production.

Performance Monitoring

Ok, so you've added the Profiler to your application and you're now measuring the performance of your components. But how do you monitor this in production?

Polaris provides a userPolaris hook that includes a logMeasurement function to measure the performance of your components in production. Let's look an example:

React
import { Profiler } from 'react';
import { usePolaris } from '@getpolaris.ai/sdk-react';

export function App() {
  const { logMeasurement } = usePolaris();

  const handleOnRender = useCallback((id, phase, actualDuration) => {
    logMeasurement(
      `${app}-${phase}`,
      'SUCCESS',
      actualDuration,
    );
  }, [logMeasurement]);

  return (
    <Profiler id="app" onRender={handleOnRender}>
      <App />
    </Profiler>
  );
}

Let's review the code above:

  • First, we import the usePolaris hook from the @getpolaris.ai/sdk-react package.
  • We then use the usePolaris hook to get the logMeasurement function.
  • We then use the logMeasurement function to log the performance of the <App /> component.
  • We use the useCallback hook to memoize the handleOnRender function to prevent unnecessary re-renders.
  • Finally, we pass the handleOnRender function to the Profiler component's onRender prop.

Create App Mount Indicator

First, let's create an indicator of performance in Polaris for the mount phase of our app:

  • Log in to Polaris and navigate to the Indicators for your application.
  • Click the Create Indicator button.
  • Enter a name for the indicator, such as Render Mount.
  • Choose a duration for the indicator, such as the Last Hour.
  • Next, choose the Rate operation to measure the duration of the performance profiling.
  • Finally, provide the following predicate function:
ESM
function main(measurement) {
  return measurement.eventName === 'app-mount';
}

The indicator predicate function above will filter all measurements sent to Polaris for those where the eventName is app-mount.

Create App Update Indicator

Next, let's create an indicator for the update phase:

  • Log in to Polaris and navigate to the Indicators for your application.
  • Click the Create Indicator button.
  • Enter a name for the indicator, such as Render Update.
  • Choose a duration for the indicator, such as the Last Hour.
  • Next, choose the Rate operation to measure the duration of the performance profiling.
  • Finally, provide the following predicate function:
ESM
function main(measurement) {
  return measurement.eventName === 'app-update';
}

Next Steps