Converting an app to React Native — Why and how
This post is part 1 of a series, and we will be posting more in the coming weeks.
With the Imagine app we aspire to help people with skin diseases track their conditions and treatment. You simply take a picture of your lesion at a fixed interval, and see if you’re improving or getting worse. Some of the most common skin conditions like psoriasis have no cure, meaning people have to find ways of coping with it. The Imagine app helps people track and understand their condition.
Why React Native?
We originally built Imagine for Android and iOS, respectively with Java and Swift. While we were happy about the actual apps, it started to become a hassle to add new features, because we needed to make them twice. We also noticed that we had slight differences in analytics, which is a pain when we try to make decisions based on data. We’d been keeping a close eye on cross-platform initiatives like Xamarin, Ionic, and React Native, and decided to look into React Native as a possible replacement for double native code.
We decided that Xamarin or Ionic would not be a good fit for our project. Xamarin was not a great option for us because we wanted to share UI code. Ionic simply did not meet our requirements when it came to performance, being a WebView-based framework. So we looked more into React Native.
The promise of React Native is that we can save on development time, especially for features that are mostly UI-based. Our initial experiments definitely showed that to be true. We had some parts that would have to stay native, like accessing the camera and using the GPU to process images, so we were happy to learn that we could re-use existing code as part of native modules or native UI components in React Native. Being able to share the analytics and business logic between the platforms would help us ensure consistency across platforms. We were a bit worried that React Native still has an immature ecosystem, and it gets breaking updates frequently. In the end, though, we decided that the pros outweigh the cons, and started the process of converting the app to React Native!
There are two possible approaches to converting an existing app to React Native:
- Add new features in React Native and replace existing features piece by piece
- Completely rewrite the app from the bottom up in React Native
In order to get the most out of the resulting app, we decided to go all in and start from scratch. That way we could set up the project the React way and go for proper idiomatic solutions all over. (We will cover our setup in a future post).
That’s one important lesson: Developers with React experience will feel at home and can start contributing to a React Native project immediately. The framework, the language, and the tools are all very web developer friendly. Flexbox styling also feels fairly familiar if you are coming from the web. The native developers, on the other hand, needed much more time to get used to an entirely new setup for writing code and running unit tests, and wrap their heads around a brand new app architecture.
The lack of strong types was also the cause of many headaches at first, but eventually we set up the proper tooling to deal with this (and this will be covered in a future blog post).
We really enjoy the quick feedback loop for building UIs using hot reloading, and that we can test those UIs on iOS and Android at the same time. That said, the development environment seems to break more easily than you would expect. We had some annoying issues with Node and NPM, where it was necessary to reset caches or even reinstall tools to get things to work again.
A lot of people claim that cross-platform apps are slower than pure native apps. Obviously there is a small delay in React Native because it still is a layer on top of the OS, but in the end, we found that to be negligible. The app does feel slow for development builds, but once we create a non-development package it feels just as fast as a pure native app. The documentation actually contains a nice write up on performance.
Having a single code base for both platforms means that API communication, business logic, and UI components only need to be written once. This is a huge time gain for the team.
React Native does require us to sometimes make compromises on the layout, and where we don’t want to do that, we need to go for custom views. This can sometimes slow us down when we work on certain parts of the app.
Another thing is the pace at which React Native gets updated. If you skip a few versions, you might end up with a painful upgrade later on. React Native gets updates every month, so it can be hard to keep up sometimes.
In the end, we are quite happy with the result, and we’re looking forward to adding new features with much more ease.
In the next few posts, we will cover some technical aspects of the move to React Native, like which tools should be included in a proper React Native development setup and how to get started on native modules and native UI components.