How to improve the performance of a React Native App?

kpiteng

kpiteng

Posted on June 28, 2021

How to improve the performance of a React Native App?

See how you will boost your react native app performance, improve start-up time, decrease bundle size & memory usage.

Key Points -
  • Hermes
  • Avoid re-rendering using useMemo
  • Cache Images
  • Use nativeDriver with Animated Library
  • State Management With Redux/MobX/Apollo
  • Remove Console Log
  • Optimize Android App Size

1. Hermes

Hermes is an open-source JavaScript engine optimized for React Native. Hermes integration helps to improve start-up time, decreased memory usage, and smaller app size.

With Hermes your app will start at 2x speed, memory usage will decrease to 30%, android app bundle size decreased 30%, iOS Application performance will boost.

Let’s see how to integrate Hermes. Hermes supports iOS support after the 0.64 version. So make sure you upgrade your app using React Native Upgrade Helper.

Enabling Hermes -

Android -
Add following code line In android/app/build.gradle

project.ext.react = [
  entryFile: "index.js",
-     enableHermes: false  // clean and rebuild if changing
+     enableHermes: true  // clean and rebuild if changing
]
Enter fullscreen mode Exit fullscreen mode

If you're using ProGuard, add following rules in proguard-rules.pro :

-keep class com.facebook.hermes.unicode.** { *; }
-keep class com.facebook.jni.** { *; }
Enter fullscreen mode Exit fullscreen mode

Clean the build

cd android && ./gradlew clean
Enter fullscreen mode Exit fullscreen mode

iOS -
Edit ios/Podfile file with below code lines -

use_react_native!(
  :path => config[:reactNativePath],
  # to enable hermes on iOS, change false to true and then install pods
-    :hermes_enabled => false
+    :hermes_enabled => true
)
Enter fullscreen mode Exit fullscreen mode

Install the Hermes pod

cd ios && pod install
Enter fullscreen mode Exit fullscreen mode

That’s it, Now create your iOS & Android build and see application start-up speed, memory usage, and specially bundle size.

2. Avoid re-rendering using useMemo

useMemo hooks helps developers to avoid re-rendering of child components to improve the performance of react application. useMemo is used to handle memoization, meaning if any component receives the same props more than once, it will use previously cached props and render the JSX view and return component.

In the sample below I have taken FlatList and Button. First time Flatlist renders perfectly. Now when user pressed button new setCount will update state variable and whole component getting reloaded with FlatList even no values updated in Array. To avoid this I have wrapped FlatListItem (UseMemoListItem) with useMemo, so useMemo checks if any change in props then only it will render the JSX else it will return render & return the view previous props.

const technology = [
  { name: 'React Native' },
  { name: 'React.js' },
  { name: 'Next.js' },
 ];
 const [arrTechnology, setArrTechnology] = useState(technology);
 const [count, setCount] = useState(0);

 function UseMemoListItem({item, onChange, arrTechnology}) {
  return useMemo(() => {
    return (
      <View style={Styles.container}>
        <Text>{item.name}</Text>
      </View>
    );
  }, [item.status]);
 }

  return (
    <View style={Styles.container}>
      <Button title='Increment' onPress={() => setCount(count + 1)} />
      <FlatList
        data={arrTechnology}
        keyExtractor={(item) => String(item.name)}
        renderItem={({item, index}) => (
          <UseMemoListItem
            item={item}
          />
        )}
        ItemSeparatorComponent={() => <UseMemoListItemSeprator />}
        showsVerticalScrollIndicator={false}
      />
    </View>
  );
Enter fullscreen mode Exit fullscreen mode

3. Cache Images

React Native Image component allow developers to display Images in application, still there is few issues like -

  • Rendering number of Image (Product List - ECommerce Application)
  • Low performance in Caching Image Loading
  • Image flickering

To solve this issue React Native support in-build caching for iOS by enabling following lines of code.

<Image
  source={{
    uri: 'https://example.com/image.png',
    cache: 'only-if-cached'
  }}
  style={{ width: 400, height: 400 }}
/>
Enter fullscreen mode Exit fullscreen mode

But, what to do for Android, there is a popular third-party library named - react-native-fast-image which will work perfect for iOS & Android. Using Fast Image you can give quick image rendering, caching mechanism and many more to application users.

import FastImage from 'react-native-fast-image'

const YourImage = () => (
    <FastImage
        style={{ width: 200, height: 200 }}
        source={{
            uri: 'https://yourimageurl.com/image.png',
            headers: { Authorization: 'token' },
            priority: FastImage.priority.normal,
        }}
        resizeMode={FastImage.resizeMode.contain}
    />
)
Enter fullscreen mode Exit fullscreen mode

4. Use nativeDriver with Animated Library

We are using animations in our Application, but sometimes it will not run smoothly as expected which impacts application render performance. To avoid flicker and run smooth animation, useNativeDriver which send animation to native bridge before animation start on component. This helps animations to be executed on separate javascript instance, which resulting in smoother animation.

It’s very simple to integration - useNativeDriver: true

Animated.timing(this.state.animatedValue, {
  toValue: 1,
  duration: 500,
  useNativeDriver: true, // <-- Add this
}).start();
Enter fullscreen mode Exit fullscreen mode

5. State Management With Redux/MobX/Apollo

Many times it is required to manage data locally means caching data which shows immediately to the user without interruption whenever the user comes back to the application. We are using AsyncStorage, Local Database Storage to store data and when the user comes back next time/ open application next time we are fetching data and keeping it in Global variables to access anywhere in the application.

To manage this in various screens and storing data into various arrays, object Prefer popular State Management Library like Redux, Redux Rematch, MobX and Apollo. These library will storage | mange | retrieve data for you and you can easily access throughout the app without any interruption.

6. Remove Console Log

All we are using console.log('Hello KPITENG!') to debug applications. While deploying an application if we keep console.log() then it will create performance issues due to javascript thread.

To remove console.log in Production, following simple installation and setup.

npm install babel-plugin-transform-remove-console
Enter fullscreen mode Exit fullscreen mode

Now, modify the .babelrc file to remove the console statements, as shown below:

{
  "env": {
    "production": {
      "plugins": ["transform-remove-console"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

7. Optimize Android App Size

React Native Android apps contain -

  • Resources such as images, fonts, etc.
  • Four different binaries compiled for different CPU architectures
  • Javascript bundle with business logic
  • Other in-built files

While you are building an app this will combine all these and create a binary for you. To optimize binary size Android build in React Native by adding below line

Update following line in android/app/build.gradle

def enableProguardInReleaseBuilds = true
Enter fullscreen mode Exit fullscreen mode

If you want to extract four different binary according your CPU architecture then,

def enableSeparateBuildPerCPUArchitecture = true
Enter fullscreen mode Exit fullscreen mode

Thanks for reading Blog!

KPITENG | DIGITAL TRANSFORMATION
www.kpiteng.com/blogs | hello@kpiteng.com
Connect | Follow Us On - Linkedin | Facebook | Instagram

💖 💪 🙅 🚩
kpiteng
kpiteng

Posted on June 28, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related