6 ways to improve the performance of React Native apps

In today’s tech scene, with people having a ton of apps on their phones, it’s not enough to just have a good idea or user-friendly design for your application. You must ensure it runs smoothly, responds fast, and impresses users. So, how can we pull that off? Well, that’s where the magic of optimizing your mobile app kicks in. It’s this kind of underrated thing in app development that really makes a difference.

Here are 6 tips on how to optimize your React Native app:

Hermes

Hermes is a JavaScript engine for React Native that precompiles JavaScript into efficient bytecode to reduce build time. Hermes has proven to be small in APK size, reduced in memory, and starts instantly, resulting in a better user experience. Hermes is specifically optimized for mobile devices, focusing on constraints like limited memory and lower processing power than desktop devices. It uses a garbage collector designed for small heap sizes, reducing the likelihood of memory leaks and improving the application’s overall performance.

To enable Hermes on Android, open your project in your preferred code editor and update your android/gradle.properties file to look like this:

If you’ve already built your app at least once, make sure to clean the build: 

Since React Native 0.64, Hermes has also run on iOS. To enable Hermes for iOS, edit your ios/Podfile file and make the change illustrated below:

If you’re on the New Architecture, you will use Hermes by default. However, you can enable/disable Hermes by specifying a value such as true or false.

Once you’ve configured it, you can install the Hermes pods with:

And that’s it! Hermes is now enabled in your application, setting you firmly on the road to enhanced optimization.
Note: It’s always recommended to test your specific application with Hermes enabled, as the impact can vary depending on its complexity and the nature of its JavaScript code.

useMemo Hook

Using ‘useMemo’ in React Native is particularly beneficial in scenarios where you have complex calculations or operations. The useMemo hook is used to memoize values, which means it will recompute the memoized value only when one of its dependencies has changed. This optimization helps to avoid expensive calculations on every render.

Let’s consider a component that calculates a number’s factorial. This calculation can be expensive, especially for large numbers. Without useMemo, this calculation would be done on every render, which is inefficient.

We can optimize this component by using useMemo. This way, the factorial calculation will only be recomputed when the number prop changes.

useCallback Hook

The primary purpose of the useCallback hook is to prevent unnecessary renders in your React application. Every time a parent component re-renders, a new function object is created. This can cause unnecessary re-rendering of child components that depend on this function.

The useCallback hook helps to prevent this by returning the same function object across multiple renders unless its dependencies change. This way, the child components receive the same function object, and unnecessary re-renders are prevented. This is particularly useful when passing callbacks to optimized child components.

Both useCallback and useMemo are React hooks used for optimization purposes. However, they serve slightly different purposes. The useCallback hook returns a memoized version of a function. Its result is a function. It is used when you want to prevent a function from being re-created every time a component re-renders.

On the other hand, useMemo returns a memoized value. Its result can be any type. It is used when you want to prevent expensive computations from being run on every render.

Use FlatList instead of ScrollView for large lists

In React Native, understanding when to use ScrollView versus FlatList is key to optimizing list performance and efficiency. For example, a ScrollView can be used to display a finite list of items, where a series of items are mapped and rendered within a scrollable view. This approach is straightforward but becomes less efficient as the list grows.

On the other hand, FlatList is specifically designed for handling larger datasets. It renders items that are only currently visible on the screen, making it highly efficient for long lists. This is because FlatList only loads and recycles the visible items as you scroll, significantly reducing memory usage and improving performance, especially for lists where the number of items dynamically changes.

Additionally, FlatList offers numerous built-in features, like onEndReached for infinite scrolling, refreshControl for pull-to-refresh functionality, and ListHeaderComponent and ListFooterComponent to add header and footer views. These features, combined with its efficient rendering for large, dynamic datasets, make FlatList a better choice than ScrollView for most list-based scenarios in React Native applications.

Optimize Images

Images are a fundamental part of modern mobile app design, and efficient image loading is crucial for delivering a smooth user experience. One of the libraries we can use for image optimization is “react-native-fast-image.”React Native’s Image component generally handles image caching like web browsers, utilizing server-provided cache control headers. However, developers often face issues like flickering, cache misses, and overall low performance in image loading and caching. FastImage addresses these problems effectively.

Why Image Caching is Important?

      • Performance: Caching reduces the time it takes to load images, especially in scenarios where the same images are displayed multiple times.

        • Data Usage: It saves data usage for users who are on limited data plans, as images are not repeatedly downloaded.

          • User Experience: Provides a smoother and more responsive user interface, as images appear more quickly.

        FastImage is an enhanced Image component replacement that utilizes SDWebImage on iOS and Glide on Android. It offers improved performance and caching efficiency in React Native applications.

        Example of FastImage use:

        Rendering many images consumes a significant amount of memory. Nevertheless, you can address this issue by optimizing the resolution and size of the images according to your application’s requirements. Opting for formats such as PNG during app development can be advantageous, and you can also consider utilizing the WEBP format, which effectively reduces image size for both Android and iOS platforms.
        If your app relies heavily on high-quality images, consider using progressive loading for larger images to improve the user experience further. This technique loads a low-quality version of the image first and then progressively improves the quality. It provides a better user experience by showing a placeholder quickly and then enhancing it.

        Debounce expensive operations

        Debouncing is another JavaScript technique that ensures a function is not called too frequently. It does so by delaying the function’s execution until a certain amount of idle time has passed since the last time it was invoked. This is particularly useful in scenarios such as search input fields where you might want to wait for the user to stop typing before making an API call or filtering data.

        This code ensures that API request will be triggered only when we stop typing for one second, reducing unnecessary API requests and improving the user experience.

        Simply, making your React Native app perform well has many benefits. It makes the app smoother and faster for users. A well-performing app keeps users around for longer, which is great for your app’s success. So, in a nutshell, making your app work well is a wise investment in happy users and a successful app.

        Read this alsoNavigate Your Way to Success: A Beginner’s Guide to React Native Navigation