React Native Performance: Major Issues And Effective Ways To Improve It

In this article, we will discuss about React Native performance, its cause as well as the way to eliminate the common performance issues in your React Native app development.

Above all, we must understand how React Native works under the hood. React Native leverages 3 main parts to run the framework: Native Thread, Javascript thread and the bridge. Here’s the actual significance and meaning of these threads:

  • Firstly, Native thread built for running Java/ Kotlin, Swift/ Objective C
  • Secondly, Javascript thread which runs everything from javascript based animations to other UI components
  • Thirdly, Bridge which acts as an intermediate communication point for the native and JS thread

Common React Native performance issues

In Android

Application size and performance on Android

An increased application size could have a drastic effect on your app’s performance. This is common problem among android apps which heavily reply on third party sources, multiple screens, libraries, etc to operate. Moreover, these added resources have a direct impact on the application size, increasing the size.

To optimize the application size of a react native application, you should:

  • Use Proguard to minimize the application size.
  • Create reduced sized APK files for specific CPU architectures. To clarify, when you do that, you app users will automatically get the relevant APK file for their specific phone’s architecture. This also eliminates the need to keep JSCore binaries that supports multiple architectures and consequently reduces the app size.
  • Moreover, compress images and other graphic elements. Another alternative to reduce image size is using file types, for instance, APNG in place of PNG files.
  • Don’t store raw JSON data. Just compress it or convert it into static object IDs.
  • Optimize native libraries.

Memory leak in Android lists

There are a couple of reasons for which memory leaks can be induced in your react native app. Take the case of scrolling in an hybrid android music application for example. On scrolling down the list of songs up to the 3rd page, the app starts freezing up RAM on mobile as well as eventually degrades performance. Since both operations occur on different parts(one in native, other in Javascript or React native part), passing this information between these two parts happens over a bridge and consumes considerable time.

Solution: Fixing memory leak due to listview

One way of fixing this is by using FlatList or VirtualizedList instead of using ListView. Using FlatList in React Native is particularly awesome when you:

  • Firstly, needs building Infinite scroll pagination
  • Needs building Pull to refresh
  • Then, needs smooth rendering performance

While FlatList performance in React Native is simply astounding for the majority of use-case, developers also use an alternative high perfo.rming interface to build better scroll experience known as SectionList.

In iOS

Animating the size of images for different UI view

In React Native applications, every time a user adjust the width or height of an image, it is re-cropped and scaled from the original image size. This process consumes a lot of memory and the app takes few seconds to load, especially for large images.

To tackle these changes, most developers use transform: [{scale}]  style property to dynamically fit the image sizes for different UI view. Moreover, to make it more memory efficient, you have to implement a custom FadeInImagecomponent to display a tiny shade.

In this approach, React Native applications can quickly project images for different UI view using the onLoad component and the cached fade in image.

Multi-threading issues in React Native

Going back to javascript threads, React Native doesn’t supports multiple threads (small unit of process) at the same time. To clarify, this is also known as multi-threading. When React Native is rendering one component, other components have to wait till the first one is rendered. Twitch had to move away from React Native because of these challenges.

In addition, when they started implementing live chat feature that runs along parallel to a live video feed, they faced major performance bottlenecks. This impacted low-end devices even more.

Build your own extension code to take care of multi-threading in React Native.

While the support for multi-threading isn’t there, we have found writing our own extension code with heavy focus on system design as well as maintainability a viable solution. You can easily write an extension code that creates a bridge between React native and native components. These extensions can be easily written using:

  • Java
  • Objective-C
  • Swift

Best practices in general that will increase React Native performance

1. Reduce Image Size and Image Caching

Images have high memory usage in react-native apps. Using large images in react-native apps have a negative impact on memory optimization. To get optimum results when dealing with images, ensure the use of small-sized images as much as possible. You may also use PNG formats as opposed to JPG image format. Finally, convert your images to web-P format whenever possible because of the following reasons:

  • WebP images speed up image loading time by 28%
  • Reduced codePush bundle size by 66%
  • Helps reduce iOS and Android binary size by 25%
  • Faster React-native JS thread
  • Smooth navigator transitions

2. Avoid Unnecessary Renders

Use PureComponentor,ShouldComponentUpdatePureComponent do a shallow comparison in props and state, while the lifecycleShouldComponentUpdate method is used in regular non-pure react components to cancel re-render by returning false in certain scenarios.

sample code

class myComponent extends React.PureComponent {
shouldComponentUpdate (nextProps, nextState) {
if( this.props.firstProp === nextProps.firstProps &&
this.props.secondProp === nextProps.secondProp) {
return false;
}
return true;
}
//
}

3. Use key attribute on list items

List is something commonly used in apps. To clarify, you should specify a unique key for each list item. So that react will not re-render every item when an item is added or removed from the list. A unique key in every list item saves react from re-rendering it again.

Sample code

lass MyComponent extends React.PureComponent {
  render() {
    return this.props.data.map((item, i) => {
      return <Text key={item.id}>{item.title}</Text>
    });
  }
}

4. Don’t update state or dispatch actions in componentWillUpdate

You should use a lifecyclecomponentWillUpdate method to prepare for an update, not to trigger another one. If your aim is to set a state,  you should do that insteadcomponentWillReceiveProps. And prefer tocomponentDidUpdate dispatch any redux actions over tocomponentWillReceiveProps be safe.

To Sum Up With React Native Performance

Overall, we see the future of React Native in bright colors. Just be aware that the framework still has some issues. However, they are mostly related to the immaturity of the technology and are likely to become less cumbersome in the future.

If you have any questions, don’t hesitate to contact us now

Tags

Share