4 min read

An important aspect of any quality mobile app is the fluidity of the user interface. Animations are used to provide a rich user experience, and any jank or jitter can negatively affect this. Animations will likely be used for all kinds of interactions, from changing between views, to reacting to a user’s touch interaction on a component. The second most important factor for high-quality animations is to make sure that they do not block the JavaScript thread. To keep animations fluid and not interrupt UI interactions, the render loop has to render each frame in 16.67 ms, so that 60 FPS can be achieved.

In this recipe, we will take a look at several techniques for improving the performance of animations in a React Native mobile app. These techniques focus in particular on preventing JavaScript execution from interrupting the main thread.

This article is taken from the book React Native Cookbook, Second Edition by Dan Ward.  In this book, you will improve your React Native mobile development skills and learn how to transition from web development to mobile development.

For this post, we’ll assume that you have a React Native app that has some animations defined.

How to do it

  1. First and foremost, when debugging animation performance in React Native, we’ll want to enable the performance monitor. To do so, show the Dev Menu (shake the device or cmd + D from the simulator) and tap Show Perf Monitor.
    The output in iOS will look something like the following screenshot:
output in iOS

The output in Android will look something like the following screenshot:

output in Android
  1. If you are looking to animate a component’s transition (opacity) or dimensions (width, height), then make sure to use LayoutAnimation.
If you want to use LayoutAnimation on Android, you need to add the following code when your application starts: UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true).
  1. If you need finite control over the animations, it is recommended that you use the Animated library that comes with React Native. This library allows you to offload all of the animation work onto the native UI thread. To do so, we have to add the useNativeDriver property to our Animated call. Let’s take a sample Animated example and offload it to the native thread:
componentWillMount() { 
  this.setState({ 
    fadeAnimimation: new Animated.Value(0) 
  }); 
}
componentDidMount() { 
Animated.timing(this.state.fadeAnimimation, { 
toValue: 1, 
useNativeDriver: true 
}).start(); 
}
Currently, only a subset of the functionality of the Animated library supports native offloading. Please refer to the There’s more section for a compatibility guide.
  1. If you are unable to offload your animation work onto the native thread, there is still a solution for providing a smooth experience. We can use the InteractionManager to execute a task after the animations have completed:
componentWillMount() { 
  this.setState({ 
    isAnimationDone: false 
  }); 
} 
componentWillUpdate() { 
  LayoutAnimation.easeInAndOut(); 
}
componentDidMount() { 
InteractionManager.runAfterInteractions(() => { 
this.setState({ 
isAnimationDone: true 
}); 
}) 
}

render() { 
if (!this.state.isAnimationDone) { 
return this.renderPlaceholder(); 
} 
return this.renderMainScene(); 
}
  1. Finally, if you are still suffering from poor performance, you’ll have to either rethink your animation strategy or implement the poorly performing view as a custom UI view component on the target platform(s). You will have to implement both your view and animation natively using the iOS and/or Android SDK.

How it works

The tips in this recipe focus on the simple goal of preventing the JavaScript thread from locking. The moment our JavaScript thread begins to drop frames (lock), we lose the ability to interact with our application, even if it’s for a fraction of a second. It may seem inconsequential, but the effect is felt immediately by a savvy user. The focus of the tips in this post is to offload animations onto the GPU. When the animation is running on the main thread (the native layer, rendered by the GPU), the user can interact with the app freely without stuttering, hanging, jank, or jitters.

There’s more

Here’s a quick reference for where useNativeDriver is usable:

Function iOS Android
style, value, propertys
decay
timing
spring
add
multiply
modulo
diffClamp
interpoloate
event
division
transform

If you liked this post, support the author by reading the book React Native Cookbook, Second Edition for enhancing your React Native mobile development skills.

Read Next

React Native 0.59 is now out with React Hooks, updated JavaScriptCore, and more!

React Native community announce March updates, post sharing the roadmap for Q4

How to create a native mobile app with React Native [Tutorial]


Subscribe to the weekly Packt Hub newsletter. We'll send you the results of our AI Now Survey, featuring data and insights from across the tech landscape.