Code with Kristian • I make videos and write about software development and programming tools
Performance Tracking in React Native
Let's take a look at how to measure render time and updates count of our React components in production.

Motivation
Whenever I happen to work on optimizing 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 a nice hefty component:
<Profiler id={"ProfileComponent"} onRender={this.onRender} />
The 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, the Profiler component is not yet stable.
Let’s get started with implementing a simple example of Profiler and Firebase Performance Tool.
Requirements 👈
- React Native ^0.57.3 🔪 (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 an alias for react-dom/profiler
and scheduler/tracing
to .babelrc
file.
Before we edit the 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, the function is asynchronous–this part is for when we later implement Firebase Performance.
Here is a quick overview of what onRender
function will return:
id: string
- Theid
value of theProfiler
tag that was measured.phase: “mount" | “update"
- Identifies whether this component has just been mounted or re-rendered, due to a change instate
orprops
.actualDuration: number
- Time spent rendering theProfiler
and its descendants for the most recent "mount" or "update" render.baseDuration: number
- Duration of the most recentrender
time for each individual component within theProfiler
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 initializing 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 the traceStarted
variable to track if trace has started. The current implementation of Firebase Perf Tool is asynchronous. The good news is that in an upcoming release, the perf tools should become synchronous (I would keep an eye on those release notes).
To keep this example very simple, I’m recording the mount time as initialMount
(if components re-mount, it will record last mount) and counter as updates
, measuring the number of times component re-renders.
On top of the initialMount and update, we are also able to record how long each re-render takes. It almost seems like the possibilities are almost endless 🤩
With this simple approach, we can add performance tracking to our most important components.
To make code more reusable, we can create our own higher-order component (HOC) for the Profiler component, and include all of our additional logic.
Should I use it in production? 🙇
This is a tricky question at the time of writing this article, since the whole feature is still flagged as unstable, and React is not using asynchronous rendering.
We can expect some minor drawbacks when using the profiler in production. Let’s take a closer look at two issues, with which I’m mostly concerned: how much additional commit time will Profiler adds to our components, and how much our bundle size will increase.
Is Profiler suitable for production?
To answer this question, we can try to measure impact before/after adding <Profiler>
component by using React Developer Tools Profiler.
My test case consist of FlatList
with native-base
<Card />
component rendered 10x.
For test purposes, I created two components with identical code. The only difference was a <Profiler />
component added to <ProfilerComponent />
.

I ran this test 10x for each component, and measured the average commit time for the component.
- commit time with Profiler:174ms
- commit time without Profiler: 166ms
As we can see, the Profiler component added roughly about 5% of additional commit time.
This result was above my expectations.
Bundle size
If we take a look at the table below, we can see that using the react-dom.profiling
bundle will increase size of our bundle very marginally – less than 1kB.

Conclusion
Based on those two results, I’ll not hesitate to use Profiler in production.
The only thing to keep in mind, that overuse of Profiler will inevitably lead to slower performance.
Happy Profiling times! 🎄
Resources
All resources I used to gather information about Profiler:
What are your thoughts? If you find this article useful don’t forget to share and give some kudos! ❤️️️️️