How to improve the performance of a React Native App?
kpiteng
Posted on June 28, 2021
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
]
If you're using ProGuard, add following rules in proguard-rules.pro :
-keep class com.facebook.hermes.unicode.** { *; }
-keep class com.facebook.jni.** { *; }
Clean the build
cd android && ./gradlew clean
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
)
Install the Hermes pod
cd ios && pod install
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>
);
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 }}
/>
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}
/>
)
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();
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
Now, modify the .babelrc file to remove the console statements, as shown below:
{
"env": {
"production": {
"plugins": ["transform-remove-console"]
}
}
}
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
If you want to extract four different binary according your CPU architecture then,
def enableSeparateBuildPerCPUArchitecture = true
Thanks for reading Blog!
KPITENG | DIGITAL TRANSFORMATION
www.kpiteng.com/blogs | hello@kpiteng.com
Connect | Follow Us On - Linkedin | Facebook | Instagram
Posted on June 28, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.