UPDATE: For the React Profiler API and setup please follow offical doc: https://reactjs.org/docs/profiler.html. Do note that stable Profiler was released in React Native 0.61.0 (react-16.9.0)

Motivation

Whenever I happen to work on optimising some component to perform better I want to see results in metrics, and ideally from users.

Unfortunately in previous versions of React Native, I could only measure performance on my own device or simulator.

In the recent React Native v57 release I discovered nice hefty component:

<Profiler id={“ProfileComponent”} onRender={this.onRender} />

Profiler component will provide us metrics for all wrapped components.

<Profiler id={"ProfileComponent"} onRender={this.onRender}>

<View>

<Text>Hi</Text>

</View>

</Profiler>

The best part about this component is not the ease of seeing metrics for our components, but the fact we can use it in production!

Just be aware that currently Profiler component is not yet stable.

Let’s get started with implementing simple example of Profiler and Firebase Performance Tool.

Requirements 👈

React Native ^0.57.3 🔪 (also possible since 0.56, but haven’t tested)

(also possible since 0.56, but haven’t tested) Ejected React Native project

Tool to record metrics (ie.: Firebase Performance Tool)

Simple implementation 🤓

1. Add alias for react-dom/profiler

To make profiling work in a production environment, we need to add alias for react-dom/profiler and scheduler/tracing to .babelrc file.

Before we edit file, we need to install this package babel-plugin-module-resolver , which bring us alias functionality.

yarn add -D babel-plugin-module-resolver

Once we got the babel plugin installed, we modify .babelrc like this:

2. Add Profiler component

We will import unstable_Profiler from React and make an alias to make our code more readable.

Implementing Profiler itself is very straightforward. Just wrap any part of code you want to measure.

Last step is to listen for onRender callback and console.log metrics with logMeasurement function. As you can see function is asynchronous, this part is for later implementation of Firebase Performance.

Here is quick overview of what onRender function will return:

id: string - The id value of the Profiler tag that was measured.

- The value of the tag that was measured. phase: “mount" | “update" - Identifies whether this component has just been mounted or re-rendered due to a change in state or props .

- Identifies whether this component has just been mounted or re-rendered due to a change in or . actualDuration: number - Time spent rendering the Profiler and its descendants for the most recent "mount" or "update" render.

- Time spent rendering the and its descendants for the most recent "mount" or "update" render. baseDuration: number - Duration of the most recent render time for each individual component within the Profiler tree.

📖 For more details, please refer to official RFCS of Profiler

Add Performance Monitoring

To record Profiler metrics I picked Firebase Performance Tool (implemented in RN via Invertase package)

I’m putting the final code upfront, so I can go through each part separately.

Since I’m initialising trace in componentDidMount I have to cache values from initial render in variables initialMount and initialUpdates . And later record those data (line 21, 22).

I’m also using traceStarted variable to track if trace has started. Current implementation of Firebase Perf Tool is asynchronous. Good news is, that in upcoming release the perf tools should become synchronous (I would keep an eye on those release notes)

To make this example very simple, I’m recording only mount time initialMount (if components re-mount, it will record last mount) and counter updates measuring number of times component re-renders.