BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles Writing Cross-Platform Apps with React Native

Writing Cross-Platform Apps with React Native

 

React Native is a JavaScript framework for writing real, natively rendering iOS and Android applications. It’s based on React, Facebook’s JavaScript library for building user interfaces, but instead of targeting the browser, it targets mobile platforms. In other words: if you're a web developer, you can use React Native to write clean, fast mobile apps, from the comfort of a familiar framework and a single JavaScript codebase.

We've heard promises of universal app development before, of course, with frameworks like Cordova or Titanium. What's it like to actually use React Native? In this article, we'll explore what React Native is and how it works. Then, we'll cover what it's like to actually use React Native to write iOS and Android applications. By the end, hopefully you'll see why React Native is a strong choice for your next mobile project!

So What is React Native?

Before we dig into the developer experience, let's talk about what React Native actually is, and a bit about how it works.

It's Just React

React is a JavaScript library for building user interfaces, normally on the web. Developed and open-sourced by Facebook in 2013, React has seen widespread adoption. React is relatively narrow in scope; it only concerns itself with rendering your application's user interface, as opposed to a larger MVC-style framework.

Developers have flocked to React for a number of reasons. It's lightweight, and offers impressive performance, especially for quickly-changing data. Because of its component structure, it also encourages you to naturally write more modular, reusable code.

React Native is just React, but for mobile. There are some differences: you'll use a <View> component rather than a <div>, and an <Image> instead of an <img> tag. The developer experience remains much the same. Having some Objective-C or Java knowledge can be useful, and mobile development does come with its own tricky considerations (have I tested this on multiple physical devices? Are my touch targets large enough?). However, React Native will feel almost entirely familiar, and comfortable, to developers who already know how to work with React in the browser.

It's Actually Native

One of the first things that surprises people about React Native is that it's "actually" native. Other JavaScript-for-mobile approaches wrap your JavaScript code in a glorified web view. They might re-implement some native UI behavior, like the animations, but you're still writing a web app.

In React, a component describes its own appearance; React then handles the rendering for you. A clean abstraction layer separates these two functions. In order to render components for the web, React uses standard HTML tags. This same abstraction layer, known as the "bridge," enables React Native to invoke the actual rendering APIs on iOS and Android. On iOS, that means that your React Native components render to real UI Views, while on Android, they'll render to native Views.

You'll write what looks an awful lot like standard JavaScript, CSS, and HTML. Instead of compiling down to native code, React Native takes your application and runs it using the host platform's JavaScript engine, without blocking the main UI thread. You get the benefits of native performance, animations, and behavior, without having to write Objective-C or Java. Other cross-platform methods of app development, such as Cordova or Titanium, can never quite match this level of native performance or appearance.

A Better Developer Experience

Compared with standard iOS and Android development, React Native offers a much stronger developer experience. Because your application is mostly just JavaScript, you get a lot of the perks of web development, like being able to instantly "refresh" your application to see your code changes. Compared to the long minutes spent waiting to rebuild a traditional mobile application, this feels like a godsend.

Additionally, React Native provides you with intelligent error reporting and standard JavaScript debugging tools, which makes mobile development a lot easier.

Handling Multiple Platforms

React Native gracefully handles multiple platforms. The vast majority of the React Native APIs are cross-platform, so you just need to write one React Native component, and it will work seamlessly on both iOS and Android. Facebook claims that their Ad Manager application has 87% code reuse across the two platforms, and I wrote a flashcard app without any platform-specific code at all.

If you do want to write platform-specific code -- due to different interaction guidelines on iOS and Android, for instance, or because you want to take advantage of a platform-specific API -- that's easy, too. React Native allows you to specify platform-specific versions of each component, which you can then integrate into the rest of your React Native application.

Working with React Native

Being able to write truly native iOS and Android apps using a single JavaScript codebase seems like a no-brainer. So what's it like to actually work with React Native?

Getting Started

To start developing React Native applications, you'll need to install the ordinary dependencies for iOS and Android development, as well as React Native. There's a good guide to this on the React Native website. Setting up React Native is simple. If you already have an updated version of Node installed, then you can install React Native with npm install -g react-native-cli.

Once your dependencies are installed, running react-native init ProjectName will auto-generate all the boilerplate you need to start a new project.

There is one catch: you'll need to use OS X in order to develop with React Native. Apple requires you to have a Mac in order to develop iOS applications, so for most developers this restriction was already unavoidable. If you want to focus on writing Android applications instead, React Native has experimental support for developing on Windows and Linux.

Ordinary React Components

Once you have your developer environment ready to go, it's time to start writing some actual applications.

As mentioned before, React Native is really just React, but with some key differences. React Native components look much like React components for the browser, but your basic building blocks have changed. In lieu of tags such as <div>, <img>, and <p>, React Native provides you with basic components such as <Text> and <View>. In the example below, the basic components used are <ScrollView>, <TouchableHighlight>, and <Text>, all of which map to Android and iOS-specific views. Using them to create a scrolling view with proper touch handling is pretty straightforward:

// iOS & Android

var React = require('react-native');
var { ScrollView, TouchableHighlight, Text } = React;

var TouchDemo = React.createClass({
  render: function() {
    return (
      <ScrollView>
        <TouchableHighlight onPress={() => console.log('pressed')}>
          <Text>Proper Touch Handling</Text>
        </TouchableHighlight>
      </ScrollView>
    );
  },
});
 

If you haven't dealt with the jumble of HTML-esque syntax and JavaScript that is JSX before, this might look a little confusing. React strongly encourages you to use JSX, and with React Native, you don't have a choice. Your rendering markup is co-located with the JavaScript that controls its behavior. This often provokes strong reactions from newcomers, but I strongly encourage you to give it a chance.

Because React Native components are so similar to normal React component, making the transition to React Native is quite easy.

Stylesheets

In order to make rendering simpler and more effective, as well as to encourage maintainable styling code, React Native implements a strict subset of CSS. This means that you don't need to learn a platform-specific way of designing your views, but it'll take you some time to learn how to use React Native's styles.

The biggest difference is that you don't have to worry about specificity rules, since style inheritance is severely curtailed and React Native uses inline style syntax.

Here's an example of how stylesheets are created in React Native:

var styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 30
  }
});
 

Then, that style is applied using inline syntax:

 
<View style={styles.container}>
	...
      </View>

The syntax is easy to read, but if you're coming from a web background you might find it a bit alarming. (There's a good reason for it, I promise!) For further reading about CSS, its problems, and React's approach to solving them, I highly recommend Christopher Chedeau's slide deck: CSS in JS.

Setting Up for Mobile Development

One of the more complex parts of React Native is the developer setup. When working with React Native, you need to have all the usual tools for mobile development, and your JavaScript editing tools: a text editor, and perhaps the Chrome developer tools for debugging.

For iOS, this means having Xcode open, as well as the iOS simulator. For Android, rather than Android Studio, you'll use the command-line tools. Finally, you'll also need to have the React Native packager running. You can choose your favorite text editor to use for editing your JavaScript code.

The net result of this is that you have lots of tools at your disposal. Sometimes it feels like too many tools, and the desktop clutter of having so many windows open can be annoying. On the flip side, at least React Native isn't hiding any of the standard mobile development process from you.

Jumping Down Into Native Code

React Native works by providing JavaScript interfaces to existing platform APIs. In practice, this means that you can write what looks like ordinary React code, and the React Native "bridge" will take care of the heavy lifting. But what happens when the bridge is incomplete?

Inevitably, with a new framework such as React Native, there will be API calls that are not supported by the framework. In that case, you can write a "native module" to communicate between the host platform and your JavaScript code. Here's a bare-bones example of a "hello, world" Objective-C module:


// Objective-C

#import "RCTBridgeModule.h"

@interface MyCustomModule : NSObject <RCTBridgeModule>
@end

@implementation MyCustomModule

RCT_EXPORT_MODULE();

// Available as NativeModules.MyCustomModule.processString
RCT_EXPORT_METHOD(processString:(NSString *)input callback:(RCTResponseSenderBlock)callback)
{
  callback(@[[input stringByReplacingOccurrencesOfString:@"Goodbye" withString:@"Hello"]]);
}
@end

Then, to use your native module from JavaScript, you require it like any other library:

// JavaScript

var React = require('react-native');
var { NativeModules, Text } = React;

var Message = React.createClass({
  getInitialState() {
    return { text: 'Goodbye World.' };
  },
  componentDidMount() {
    NativeModules.MyCustomModule.processString(this.state.text, (text) => {
      this.setState({text});
    });
  },
  render: function() {
    return (
      <Text>{this.state.text}</Text>
    );
  }
});

You might do this if an API you need is not yet supported, if you want to integrate your React Native components with existing Objective-C or Java code, or if you need to write some high-performance function to handle some intensive graphics processing. Happily, React Native gives you the flexibility to write and use these so-called "native modules" when you need to, and the process is straightforward. Even if you've never worked with Objective-C or Java before, writing the "bridge" code is a great exercise in getting comfortable with native mobile development.

Deploying Your Applications

Deploying React Native applications is very similar to working with ordinary mobile applications. That doesn't mean it's easy, as the mobile release process is known for its headaches.

To create a deploy-ready bundle, you'll need to switch to using bundled JavaScript instead of the live-reloading development version. On iOS, this means making a one-line change to your AppDelegate.m file, and running react-native bundle --minify. For Android, you'll run ./gradlew assembleRelease. After that, the bundling process is the same as for an ordinary mobile application, and the resulting bundle can be submitted to the relevant app store(s).

The iOS App Store took two weeks to approve my flashcard application, while the Google Play Store took less than a day. In other words, approval times were exactly in line with what I would expect for a "traditional" mobile application, with no penalty applied for it being built with React Native.

Intriguingly, Apple allows applications to update themselves -- thus circumventing the normal headaches of the deploy process -- if the updates are JavaScript-only. Microsoft recently released its CodePush SDK, which enables React Native developers to push updates out instantly. It's a tantalizing option, and I expect to see more applications taking advantage of it in the coming months.

Conclusions and Recommendations

If you're coming from a web-based JavaScript background, I think you'll be delighted by React Native. React Native turns any web developer into a potential mobile developer, and delivers a strong improvement on the existing mobile development process.

React Native isn't without its drawbacks. It's still a new project, and comes with the headaches of any immature library: some features are missing, and best practices are still being discovered. Breaking changes between releases, though few and limited in scope, do still occur.

However, React Native is sufficiently mature that the benefits outweigh these drawbacks. With React Native, you can use a single JavaScript codebase to create both iOS and Android applications, without compromising on quality or performance. Even if you aren't coming from a JavaScript background, it's hard to argue with the benefits of a faster development cycle and near-total code reuse. And because React Native lets you drop down into "normal" development when you need to, you're not handicapped by the framework's limitations. All told, React Native delivers on its promise of high-quality, cross-platform mobile development, and if you're starting a mobile project, you should be giving it serious consideration.

If you want to read further, my book, Learning React Native, is available in both print and eBook editions from O'Reilly and Amazon. You can also find me on Twitter as @brindelle. I'd love to hear about your experiences and questions regarding React Native!

About the Author

Bonnie Eisenman is a software engineer at Twitter and a member of the hackerspace NYC Resistor, with previous experience at Codecademy, Fog Creek Software, and Google. She is the author of Learning React Native, a book on building native iOS and Android applications with Javascript, published with O'Reilly Media. She has spoken at several conferences on topics ranging from ReactJS, to musical programming and Arduinos. In her spare time, she enjoys learning languages, tinkering with hardware projects, and laser-cutting chocolate. Find her on Twitter as @brindelle.

Rate this Article

Adoption
Style

BT