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?
- 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 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
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 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
Images contribute immensely to high memory usage in React Native apps. No wonder, image optimization is critical in improving app performance.
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
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.
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
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.
You should convert raw JSON data to simple objects before rendering.
5. Large App Sizes
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.
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.
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
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.
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
If your application contains a map feature, you will discover that the navigation and dragging features are quite slow in React Native.
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.
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.
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
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.
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.
The Final Word
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.