What is a React Native application?
React by itself is a JavaScript library for building web user interfaces. Combined with mobile native-development tools & APIs, React Native allows developers to build native mobile-apps using the same known library from the web. Developers can write their UI & logic code once in JS and publish it to multiple platforms (such as Android, iOS, Web etc.)
Unlike other frameworks, React Native uses NATIVE UI elements & APIs and doesn’t wrap the app with a Webview in order to render its view.
How to investigate React Native apps performance issues?
Since these apps use native elements (UI & APIs), performance issues can occur due to problems either on the native side (at each one of the platforms), the JS code or the communication between both.
To investigate and find the source of the problem, the first step to take (as in any good debugging) is to isolate the problems. Here are some suggestions and examples of issues testing and isolating:
1. Check different versions of the operating system or the devices
If a button responds slowly only on iOS or the animation is stuck on Android, the issue may be in the code implementation of this specific platform.
2. Check different versions of the operating system or the devices
Devices are not divided into only 2-3 main platforms. There are a lot of versions for the same operating system and issues can be a result of old operating system versions, old devices or unsupported features. Problems related to network loading (HTTP/S), accessing to the file-system (in specific directory or without the relevant permissions), images not being displayed or errors in showing a heavy screen are good examples for this type of issues, and the solution will be to update the code to support these different versions (either in the JS code or the native code of each platform) and sometimes even to upgrade react-native itself.
3. Search for complex tasks in the communication between native and JS
For example, when using animations or virtualized lists (Flatlist, SectionList etc.), there is a lot of data that is being transferred from and to the native side. While the logic processing is being done on JS code, the UI changes and the rendering are being managed on the native side. Complex and “hard work” calculations in JS may lead to slowness and performance issues in the app and should be simplified.
4. Check the influence of native abilities
Some React Native features rely on native components and even other apps to work properly, for example: Camera, Download Managers or WebView. Unplanned updates for these components may affect the performance of the app and sometimes even lead to unexpected issues while using them.
Common performance and slowness issues in React Native
Besides the influence of the native side in a React Native application, Bad-written code in JS which does not follow React guidelines is another main source for performance issues. Here are some common mistakes and points that can be investigated:
1. Multiple renders
Make sure to prevent unnecessary renders by updating states and props only when needed. Pass only required props to a component (extra props that do not actually being used in the component may cause the component to render itself), improve hooks and correctly manage their dependencies, avoid updating states as side effect for fetching data etc. Pay attention that although React will merge setState for a single render, it is not always the case. Multiple calls to setState inside events or hooks may lead to unwanted multiple renders.
2. Libraries Dependencies & Imports
Reduce the usage of heavy dependencies (and a lot of them), consider if you really need them (do not import a large module just to loop over an array or to assign a new value to an object) and prefer using Inline Requires to delay the requiring of modules and files until they actually needed.
3. Destroying & Re-creating screens and components
When changing the UI view, either by navigators, tabs or simple buttons that replace the whole view, the relevant components in the screen may unmount themselves. Sometimes, this unmounting is not planned and may lead to slowness during the destruction and then on the recreation of the component. Developers should consider what is the expected result in these situations and how it will not affect the logic & the performance of the app.
4. Fetching data for not-in-focus screens & Lack of Caching Mechanism
Hooks & components events may lead to a reload of data on unexpected times. Fetching data should be placed on specific events that can be monitored and limited, for example: button-click or component mount etc. Moreover, relevant calls should be saved/cached in a store for preventing reloading of the same data when nothing was changed. It is particularly important to monitor these calls and make sure that they do not occur at unexpected times such as after recreating a component (as described in bullet #3) or triggered multiple times by an event on another screen.
5. Unexpected large size of data
While developing the app and using mock data, there may be usage of small data structures. It may look that everything works perfectly and loads fast, but after moving to a staging/production environment – things may start to get stuck. For example, when using lists – always make sure to check a large range of inputs: 0 items, 1 item, 2-100 items, 1000+ items and more. Even if there is no usage of lists in the app, each response from the server has the potential to become larger than expected and should be handled & stored correctly. Think about the following examples: large objects with members data, app initialization information, translation strings etc.
6. Large images and resources
In addition to the last bullet, almost every app uses images for decoration or for displaying easy-to-understand data. More rare but not unusual are videos and audio files that are being used in the app. All these resources should be compressed and minified to prevent slowing down the app loading. This includes local resources being saved in the app and remote resources being loaded from a server.
Few words about Server Side that can affect app performance
Although server side improvements are out of the scope of this article, don’t forget that it has an influence on the performance of your application. Slow loading times, unoptimized responses that are stored in the app-memory, lack of pagination, too-many requests that are being called at the same time, sequence of multiple calls to retrieve data and more – all of these may lead to bad performance in the application and should be investigated and improved.
Conclusions
Debugging issues, and especially performance issues, isn’t an easy task. Always start by isolating the problem and define its type. Try to remove non-related elements from the app to identify the exact spot to begin with. Make sure that there aren’t screens, components, events or data fetching that influence your tests and prevent you from solving the problem. Use recommended debugging-tools (and even console logs!) when possible to reveal the hidden problems and to trace what is happening in your app
If you need further assistance, don't hesitate to contact us for expert help.
Good Luck! 🙂