An app is considered to have bad performance if it responds slowly, shows slow animations, freezes, crashes, or uses a lot of battery power. However, we can avoid all these performance issues with something called «profiling». If you need to identify why your app is experiencing lousy performance related to network, memory, graphics, or CPU… keep reading.
Profiling Overview
Profiling is a tool that helps us to explore our app deeply. That’s why on this blog post we will go through a set of tools that we can use when we experiment bad app performance!
First of all, Profiling is used to get detailed information about how the JavaScript thread is working. It is a set of tools that helps us find performance delays, and see the threads that are working. So, to access the profiling monitor on React Native you have to use the Pef monitor from the debug menu.
You can use native tools for Android or iOS and use the systrace. And, there is another way to see the thread information with the chrome debugging tools. Here, we will see how to use it —and the information we get— with this tool.
Different tools can help us see the app’s performance and the threads that we are using. So, use profiling if you find something wrong related to your app’s performance, or if you want to find issues related to the UI or GPU.
iOS Profiler
Xcode provides a toolset that supports profiling, CPU profiling, time profiling, and network profiling natively. React Native can access these tools with the .xcworkspace inside the iOS folder.
To do so, open your project on the folder browser and go to the iOS folder. Then search for a file with the .xcworkspace extension and click on it.
Next, we will see the Xcode opened. There, we need to run the app with the Xcode.
Once the app is opened and running, we can go to “Debug Monitor.”
We can see three different options to analyze the memory leaks: CPU usage (depending on the device), Disk usage, and Network calls.
When we open the memory usage, we are going to see this screen:
Now, interact with your app, open or close screens to detect issues, and see its behavior. Usually, you have memory leaks when:
- The app takes too long to open
- The app closes when you touch some feature
- The navigation takes too long to charge
- The typing on forms takes too long to change the value
These memory leaks could be easy to find, but it could take us some time to fix them, and even more, if they are related to performance.
Android Profiler
Like the iOS side, we have a native profiler for Android. In this case, you can access all these features by opening the android folder into Android studio. Once the project is opened into the android studio, run the project. Follow these steps to open the profiler:
- Open the android folder inside the android studio
- On Android, studio bottom looks for the profiling icon and clicks on it
- We are going to see a screen with detailed information about your app
The profiler allows us to see the memory used, CPU usage, and disk usage.
If we interact with the app, we can see the memory usage and the memory leaks, we can also see the filtered data fby CPU, memory, or energy. This happens if the app manages the memory allocations poorly. Memory leaks also occur when an object is stored in memory, but the app cannot read it. You can fix these bugs, but you will need profiling’s help to debug the app. All in all, profiling tools are powerful for testing our app while interacting with it and identifying wrong paths.
The Debug
Debugging is the process of finding and fixing errors within a script. In fact, the most modern browsers contain debugging tools that can be used easily with React Native. To sum up, we can discover JavaScript bugs by using Google Chrome console. So, we can use the debug tool following the next steps:
1.- Enable the debug option on the menu with command + m and click on the debug menu:
2.- Add the keyboard debugger on the line that you need to review:
3.- It will open the debugger into our browser. We can now see a descriptive console with all the results that we need to review.
As we can see, if we follow these simple steps, we can debug our code in a better way, and also we can see step by step the function’s workflow. Also, we can find leaks with this technique because we can stop the code wherever is needed.
Chrome debugging profile
We also have a generic tool instead of using iOS or Android native profiling tools. In fact, we can use Google Chrome debugging tools and review the performance efficiently. To do so, follow these steps:
- Open the app and run the React Native debug menu. It will open the chrome console.
-
Click on the Performance tab.
Chrome debugging tools help to profile all the data related to the React Native app. Use it to improve your functions and components.
Error boundaries
We can use error boundaries to create components to catch errors anywhere on the component tree. Error boundaries can catch errors in the render, lifecycle methods, and constructors. Here we have two kinds of errors:
JS Exceptions: Errors produced by JavaScript code, including errors related to react core.
Native Exceptions: Error produced by Native Modules.
If we have JS exceptions that means we have to use, try, and catch methods with imperative code. The react components are declarative, so we need to use the native modules from React which are called error boundaries.
Error boundaries are supported by React 16. It catches all the errors generated by the component tree.
We can use error boundaries API only with a class component, and every class component can call the methods.
- getDerivedStateFromError()
- componentDidCatch
We can wrap every navigation screen in our application with react-error-boundary.
Install the dependency:
yarn add react-error-boundary
Now modify your document in a text like this:
import * as React from "react";
import { ErrorBoundary } from "react-error-boundary";
import { View, StyleSheet, Button } from "react-native";
import { Text } from "components";
const myErrorHandler = (error: Error) => {
// Do something with the error
};
function ErrorFallback({ resetErrorBoundary }) {
return (
<View style={[styles.container]}>
<View>
<Text> Something went wrong: </Text>
<Button title="try Again" onPress={resetErrorBoundary} />
</View>
</View>
);
}
export const ErrorHandler = ({ children }: { children: React.ReactNode }) => (
<ErrorBoundary
FallbackComponent={ErrorFallback}
onError={myErrorHandler}>
{children}
</ErrorBoundary>
);
Now we can use the error boundary to find bugs and let the user know that everything will be just fine.
Conclusion
To sum up, you can improve your React Native app with a mix of good tools, good practices on your code, and great teamwork.
Surely, external tools improve the builds and keep the code quality; choose one or a mix of them.
In the end, many tools can help us to increase performance, but I recommend you to use them wisely, taking into account the situation.
Hope this info works for you. Thanks for reading!