A report by Google found that 53% of visitors leave the website or app that takes more than 3 seconds to load. This means that every second your app fails to load, you lose potential clients.

Therefore, in this post, we will be focusing o    n improving the performance of React Native apps and will discuss in length the problem that a website developer may face. Developing an app with React Native is not that challenging as keeping up with the app’s performance.

How React Native Applications Work?

React Native uses Javascript and communicates with the native components through a bridge. React Native depends on 3 primary threads:

  • The shadow tree thread
  • The UI thread
  • The native thread

The main part of the React Native app consists of:

  • The native part that runs on Objective-C, Java or Swift
  • React Native that is built using Javascript

React Native Performance Tips

Looking at the React Native GitHub page, you will see that developers are reporting lots of errors and issues. These issues are either implementational or inherent. In this post, we will discuss the major issues that slow down your app. Understanding how to solve these will help you deal with other problems as well.

1. Memory Issues

The Problem

Memory leaks are one of the main problems, particularly for Android apps built on React Native because of many unnecessary background processes.

You can find leaks using XCode as follows:

a. Navigate to XCode > Product > Profile
b. Choose Leaks

You can find memory leaks using Android Studio as follows:

a. Start your React Native app normally
b. Run Android Studio
c. Navigate to Tools > Android > Enable ADB Integration
d. Click on Tools > Android > Android Device Monitor
e. After the Android Device Monitor starts, click on Monitor > Preferences
f. Use Perf Monitor to identify any memory leaks

The Solution

The best way to solve the memory leak problem in React Native applications is to utilize scrolling lists like SectionList, FlatList, or VirtualizedList instead of Listview. Additionally, the scrolling list helps to smooth the infinite scroll pagination.

This is important if you are building an application with many data points and that has a pull to refresh feature.

2. Image Size Problems

The Problem

Images contribute immensely to high memory usage in React Native apps. No wonder, image optimization is critical in improving app performance.

The Solution

To solve the high memory usage problem caused by images, you should do the following:

a. Reduce the sizes of your images

Optimizing images is one of the easiest, but most important ways to optimize performance. You should optimize image resolution, image size and format to improve performance. Please consider the following actions:

  • Use GZip compression for SVG images.
  • Remove image metadata.
  • Resize images so that you serve the right image for the right screen size.
  • Reduce the number of images.

b. Convert your images to WebP format

The benefit of using WebP format is that it can reduce the loading time of the image by as much as 28%. The WebP format also helps reduce the CodePush bundle size by 66%. Additionally, it helps reduce Android and iOS binary size.

In addition to that, the Navigator transitions are a lot smoother and the React Native thread feels a lot faster.

c. Use PNG rather than JPEG format

In case your app’s color palette is less than 256 colors like for animations or comics, you should use GIF images. For animations where image scalability is required, the SVG format is preferable. You should play around with image formats and resolutions to ensure that your app offers the best performance.

d. Local Image Caching

Image caching is where the app stores a copy of the image on the phone’s memory. Therefore, this helps load the images faster. The bad news is that at the moment, image caching is only available on iOS.

On Android, you can use some npm libraries to solve the image caching issue. The disadvantage is that they don’t offer the best performance.

3. Unnecessary Renders

The Problem

You need to be very careful when implementing the diff state, lifecycle and props (it passes as properties in component). This prevents you from passing too much work to the Reconciler, which may result in the dropping of the thread’s FPS.

The Solution

Use the ‘shouldComponentUpdate’ lifecycle method as a Boolean (it returns true or false on which we decide if component to be rerendered or not). This helps determine whether the component should update. Plus, you should prefer creating a small number of components.

4. Optimize JSON Data

The Problem

Mobile applications will always need to load resources from remote URLs and services. This is why you need to make fetch requests to get data from a remote server.

Whether you are pulling data from a private or public API, you will receive data in JSON format, which consists of compound nested objects. What most developers do is that they use the same JSON received. This is a bad idea because your application’s performance suffers as Javascript renders JSON slowly.

The solution

You should convert raw JSON data to simple objects before rendering.

5. Large App Sizes

The Problem

Since you mostly use external libraries, this tends to affect the application’s size. Reducing the application’s size is all about resource optimization. There are several ways to deal with this problem.

The Solution

So as to reduce the application size, you can use ProGuard, which helps you create different application sizes for devices on a different architecture. Also, do not forget to compress graphical elements such as images.

You can also move components from the native realm to the React Native realm. The Javascript components use a bridge to communicate with the native side. Reducing the application size reduces the load on the bridge, improving the app’s performance.

Additionally, boilerplate code from libraries tends to slow down the render process. There are components that heavily use message queues when communicating with the native side. It’s a good idea not to pass them to the native thread.

6. Frozen UI in React Native

The Problem

A frozen user interface occurs when there is a long operation on the main thread, which blocks the UI thread from rendering. This problem worsens when rendering large files, custom animations, raw JSON, and map data.

The Solution

To fix the frozen UI issue, you should avoid Object Finalizers and avoid running heavy objects on the main thread.

7. Using Maps in React Native Applications

The Problem

If your application contains a map feature, you will discover that the navigation and dragging features are quite slow in React Native.

The Solution

When integrating the map feature in your application, remember to remove console.log, so that it does not store any data in XCode. Also, you should disable the auto-update of geographical regions.

As you can see, the objective is to reduce the load time of the Javascript thread, which improves interactions with the map.

8. Multithreading

The Problem

React Native does not support multithreading, which means that several services cannot run at the same time. This means that when React Native is rendering one component, the other components should wait while the first one is being rendered.

The Solution

If your app needs a multithreading feature, then you should probably build your application using a technology that supports multithreading. For example, Twitch was forced to move away from React Native because they could not have a live video feed and a live chat feature.

9. Device Orientation

The Problem

It has been observed that some React Native apps crash once the screen orientation changes. This alone might result in the loss of users, particularly video and gaming enthusiasts.

The Solution

At first, developers thought that react-native-orientation was one of the solutions. However, react-native-navigation cannot determine the orientation lock on iOS devices.

For more reliable results with device orientation, your application should listen to the app’s root view.

Other Ways to Optimize Your React Native App

a. Use PureComponent

In React, the PureComponent is a component whose return value is determined by its inputs and the return value is always the same for the same input values. They just use the data passed in via props.

Only when the props change does the app re-render. In components that are not PureComponent, the shouldComponentUpdate lifecycle method helps cancel unnecessary re-renders and returns false in certain scenarios.

b. Using the NativeDriver Animation

React Native animations look good and are easy to create. The animation library of React Native allows you to use the native driver and sends animations across the bridge to the native side before the animation starts.

Animations use the main thread, which is independent of a blocked Javascript thread. The result is a smoother animation and fewer frame drops. This is why you should use the React Native Driver as your animation configuration.

The Final Word

React Native presents an amazing opportunity for both mobile app development companies and developers. It makes it possible to write an application for Android and iOS using one language: Javascript.

However, as this post shows, there are various things that can slow down your app. The good news is that these problems have a solution, and can help improve your app’s performance.

Let me know if you think we have missed any of the React Native best practices by commenting below and our expert panel will surely look into it.