Not long after starting React Native development, I started to look at the apps on my phone in a very different way. For every delightful user experience, I would wonder: can we implement the same user experience using primitives from the React Native world? This is how the “Can it be done in React Native?” YouTube series was born.

Each episode follows the same structure: we discuss an example from an app people know and love and implement it with React Native.

In each episode, we look at a user-experience from an app people know and love, like Instagram, Snapchat, and so one. We discuss what makes the example exciting to look at, how we would implement it using React Native and finally we write the actual implementation. The source code of every episode is also available on GitHub.

In this story, we will give the rule of the game: what qualifies something as being doable or not doable in React Native? Then we will go over some of the recipes and common patterns that emerged while doing the show.

🎲 The rule of the game

“When speaking of animations, the key to success is to avoid frame drops”.

Krzysztof Magiera

In React Native development, the rule of the game is for your app to run at 60 fps even on low-end Android devices. This can be achieved by using declarative gestures and animations that allow you to stay on the native side as much as possible. Since the communication between the JavaScript and the native userland is asynchronous, a command that goes over the bridge is likely to be processed in an amount of time higher than 1/60 seconds.

The current tradeoffs of using React Native gesture and animations explained by the man himself: Krzysztof Magiera

In his talk at React Europe 2018, Krzystof Magiera made a strong an elegant case for declarative gestures and animations in React Native. I strongly recommend you check it out.

In this example, the gesture handling and animation are executed on the Native thread, life is good.

In the example above, we overlay two components: <Cards> and <ScrollView> . The y animation value from the ScrollView drives the animation of the cards. Everything will be executed on the native thread, providing a butter-smooth user experience even on low-end Android devices. Life is good. But of course, life is not always that easy. Sometimes we need do need to cross the React Native bridge. And if we need to do it, we need to be clever about it.

Here we need to cross the React Native bridge in order to update the text values in each circle.

On the example above we need to update the text value inside each circle. The first step will be to use setNativeProps in order to avoid a re-rendering on the React side. On top of that, we will also need to use some sort of schedule according to the type of effect we are trying to achieve. A combination of requestAnimationFrame() and throttle() for instance.

Or sometimes being clever can also mean finding a way to not cross the bridge it at all.

The zen play button from the Headspace meditation app.

In the case of the play button from the Headspace meditation app, we first thought of a solution that would require us to cross the bridge between the JS and UI thread. The circle is defined as an SVG path, we have different versions of the circle and we use SVG path morphing with some scheduling in order to display the current state of the circle. This will work great on iOS because the iPhones are powerful devices but it will look somewhat clunky on low-end Android devices. Can we avoid to cross the bridge in this case? Another solution would be to build the animation with Adobe After Effects and use Lottie to run it on React Native. Or as a subscriber of the channel suggested it, we can actually achieve the same effect by overlaying four circles on top of each other and apply some slight translations on each of them. That way, we get a great result on every device.