In the first part of this article we’ve been focusing on debugging React Native apps through React Native Debugger, Chrome or other tools which main goal was displaying the output of Javascript console and inspecting variable contents. This part will cover our app’s performance check which could be a good starting point of every optimisation process.

Let’s start with some theory. To be able to successfully speed up our app it’s important to understand some concepts behind the communication between Javascript and Native part of React Native and how it handles operations.

One thing you need to know and understand is that, there are two separate worlds which exist simultaneously in our React Native apps – JavaScript, in which you write your code and Native, iOS/Android world, speaking more low level.

In order to be able to provide developers with such a smooth and easy experience and let them code mobile apps in their favourite programming language, which of course is Javascript, some sort of communication has to exist. In simplification, you write your app in Javascript, giving it instructions how it should look and behave and those commands have to be transmitted to the Native world, and more importantly they have to be available to be understood by it.

Part of React Native responsible for handling JS and Native communication is called the bridge.

If you previously worked with some backend code you probably heard the concept of message queues (like Kafka, RabbitMQ etc). Their job is to receive the message with a payload and transmit it to another part of our backend services. The bridge in React Native acts the same way. It gets our Javascript queries, transform them to JSON payloads, and call the responsible Native modules. All the communication is made asynchronously which makes it a non-blocking operation.

But, the bridge can be too busy sometimes

While addressing performance issues, a good thing to know is how to check what’s going through our bridge. Awareness is a first step of making optimisations.

One way to do it, is through providing a spy function to the MessageQueue module:

import MessageQueue from 'react-native/Libraries/BatchedBridge/MessageQueue.js';

MessageQueue.spy(msg => { console.log(msg) });

It produces an output with the following structure:

{
    type: “…", // The call type: 1 means that the call was made from JS to Native, 0 otherwise
    module: “…", // Called module
    method: “…", // Module method
    args: “…" // Passed args
}

There is also another way of diving into React Native’s Bridge communication – npm module called Snoopy.

Snoopy gives you some more abilities to filter message queue calls based on where they came from, module name or called method.

JavaScript performance

Great tool for detecting performance issues in our Javascript code is React Native Slowlog, which in just a single line of code in your View, allows you to find slow operations.

Getting started with React Native Slowlog is quite easy. All you need to do is installing it via npm:

npm i -S react-native-slowlog

After that, add just one line in your component’s constructor:

slowlog(this, /.*/)

Then when running your app, you’ll see a yellow box (which React Native normally uses shows warnings) which calls were slow and time of their execution.

Common performance pitfalls

  • slow navigation
  • memory leaks
  • waiting for blocking operations instead of asynchronous calls
  • large lists and infinite scroll

Avoiding these should make your app run smoother. Also when your app runs slow, they are good starting points to make optimisations.

I hope these small tips will be a good inspiration for you in your journey to creating reliable, fast and secure apps in React Native.

In case you need more insight into your app’s performance metrics you should consider running your production build with Android’s systrace or Instruments on iOS. They’re well covered in the official RN docs Performance chapter.