Who should consider using React Native?

React Native is a really great choice for small teams that are making new apps that don’t rely too much on too many platform-specific native libraries. Most new apps will fall into this category. We think using React Native is an easy decision in those cases. It’s helped our team iterate and learn way faster than we would have been able to otherwise.

We think there are advantages that can make it useful in other situations too. There are some downsides to using it in an already established app though, which we’ll call out below.

Our team

I’ve done native Android development professionally for several years, and had a little native iOS and React web development experience from side projects. The CEO / original cofounder of our team has a React background. Neither of us had used React Native before CoffeeBreak, and we’ve been using it from the start.

What are some of the advantages?

The biggest benefit is being able to iterate and ship to both platforms at the same time. There’s some amount of platform-specific code, but it’s pretty small. We can iterate and fix bugs almost twice as fast compared to maintaining separate codebases. This is killer when you’re trying to build and learn fast with limited resources.

We also use NodeJS on our backend, and being able to share models and request/response typings easily between our API, the mobile apps, and our Admin app (a web app using React) is very useful. While we can’t share much other code between backend and frontend, being able to use some of the same libraries, like lodash for data manipulation, also reduces learning overhead.

Hot reloading with React Native is really nice and leads to much faster dev time. You can write code and see the changes in a matter of seconds, rather than a minute or longer of builds with native development. Native Android has some hotloading support, but React Native’s has worked much better than the last time I tried on Android.

I also find React’s framework and view layout much easier to work with than either the native Android or iOS framework. I didn’t expect that to be the case, but it’s helped us move much faster. I’d like to write a more in depth article comparing the frameworks later. In particular, writing reusable components feels much easier.

How do you deal with platform differentiation?

Mike Castleman at Airbnb says you can “Write 1.1 times, run in 2 places”. I think this summarizes things well – you’ll need to write differentiated code sometimes, but it’s not that frequent, and it’s nice being able to do it without switching to a different framework / language.

Out of the box, most UI elements just work. A React Native Button will look like an iOS button on iOS, and an Android button on Android. Most libraries (like React Navigation, which handles app navigation) also have components that just look and feel right on both platforms.

We don’t find ourselves needing to write platform specific logic very often at all. We know we could be doing more (for example, using FABs when appropriate on Android), but the nice thing about React Native is that we can incrementally add those enhancements over time.

Here are a few places we’ve written platform-specific code: - Slight tweaks to fine tune the spacing for some layouts, but this doesn’t happen too often. - On iOS, we usually use text buttons in the navigation toolbar. On Android, we usually use icon buttons, and when we use text buttons they’re in all caps. - Permissions logic. Using notifications requires a permission prompt on iOS but not on Android. Also, the flows for prompting permission are a little different on each platform. We’d like to write a follow-up article about this sometime. This is our most complicated platform-specific logic in the app.

If you do need to write platform-specific logic, there are two easy ways to do it. One is to write conditional logic using Platform.OS or Platform.select().

if (Platform.OS === 'ios') {
    promptForNotificationPermission();
}

let padding = Platform.select({
    ios: 8,
    android: 10
});

In cases where you really want to totally differentiate the logic for the some component, you can create two versions of the component that take the same properties, and put .ios and .android in the filenames. For example, specialButton.ios.js and specialButton.android.js.

What if I need to write some actual native code?

You might want to write native code if you’re writing something that involves a lot of quick call to the native SDK, such as a more complex custom animation that involves lots of transitions and callbacks. You might also need to call into an SDK that hasn’t been ported to React Native yet. You can write a Native Module on both the Android and iOS side, and call into it from your React Native code.

For example, we use Amplitude for our analytics tracking. Amplitude hasn’t provided an official React Native SDK, but has native ones for Android and iOS. There wasn’t a React Native library yet (although a 3rd party developer has since open sourced one), so we wrote a shim ourselves. It was pretty simple, and we only wrote wrapper methods for the calls we needed to make.

Is it really a good idea to use a cross platform tool?

Yes. I never thought I’d say that, especially after doing native development and seeing how poorly apps made with frameworks like Cordova and PhoneGap looked and felt. React Native has made huge improvements to performance and native feel over other cross platform tools.

React Native isn’t running in a WebView – it’s actually rendering native components. While the logic is evaluated in JavaScript, the UI ends up feeling native because it is native. This question on StackOverflow explains a bit about how this works under the hood, and how it can happen in a performant way, but you don’t need to know these details to be successful with React Native.

What if I can’t stand untyped languages?

Us too. We use TypeScript to add typings to JavaScript. We’d go insane without it, and it makes all the difference.

Why might I not want to use React Native?

If you’re making heavy use of platform specific libraries (e.g. an AR app using ARKit), then going native is probably a better option. React Native would probably be a bad choice for Pokémon Go.

If you already have established native apps on both platforms, integrating React Native is possible, but will likely create more trouble than it’s worth. Both Udacity and Airbnb have written about turning away from React Native after integrating it with their existing apps (although Instagram has had good success using it in some of their flows). If you’ve already written a lot of custom view elements and styling logic, then you’d need to port and maintain those in React Native as well. Otherwise, the look and feel of your app will look very different when you jump from the native parts to the React Native parts. Adding that maintenance overhead to your codebase defeats a lot of the point of using React Native in the first place. You’re also adding another layer of build complexity and dependency management, which is just one more pain if your iOS and Android builds already have a lot of complexity by this point.

Will CoffeeBreak use React Native for the long haul?

Time will tell, but probably. Several larger and well resourced companies have tried it and turned away from it, but a lot of the problems these companies faced came from adding React Native to already existing native apps. Sprinkling a little native code into a React Native app doesn’t seem to be nearly as painful as sprinkling React Native into an established app. Plus, React Native as a platform is moving fast and maturing quickly, so a lot of the potential challenges and limitations that haven’t hurt us yet will likely be non-issues, or at least less painful, by the time we run into them.