Want to see the full-length video right now for free?
Sign In with GitHub for Free AccessReact Native is a project from Facebook that allows developers to use React to build native mobile applications. This presents an amazing opportunity as now we can use the same tools, workflows, and approach to build for both web and mobile, without sacrificing the native look and interactions users expect on mobile. Join thoughtbot iOS developer Giles Van Gruisen as he guides us into the world of React Native and explains why this is so exciting.
At the core, React Native is just React. There are many additional pieces that have been added to make React run on the native Android and iOS platforms, but at its core, this is still just React. The same component-based, declarative approach to building UIs that React popularized for the web is now available in the realm of mobile.
This is great for two reasons. One, React is a very interesting framework that brings a lot of great ideas forward, particularly the idea of designing dynamic web applications using a declarative, functional approach. Your UI is a function of the current state of the application data model, and that simplicity does wonders for helping us manage complexity and keep our applications as straightforward and maintainable as possible. Check out our Weekly Iteration episode on React for more detail on the core philosophy of React and why we like it.
Second, React Native makes it possible for developers who historically have stuck to the web to now build for mobile. React Native abstracts away most of the specifics of the mobile platforms and lets developers use the same approach they've used with React on the web, while still accessing and using platform specific UI elements and interactions as needed. The philosophy is summed up well in this quote from the React Native blog:
It's worth noting that we're not chasing "write once, run anywhere." Different platforms have different looks, feels, and capabilities, and as such, we should still be developing discrete apps for each platform, but the same set of engineers should be able to build applications for whatever platform they choose, without needing to learn a fundamentally different set of technologies for each. We call this approach "learn once, write anywhere."
React Native also makes designing mobile applications much more straightforward and familiar, very similar to what it does for developing the applications. The combination of the HTML-like JSX syntax and the use of CSS-like styling (including support for flexbox layout!) makes designing React Native mobile applications a much more familiar and approachable task for designers with a web background.
This is very different from how design and layout work on the mobile platforms by default, and is a welcome change. Again, the power here comes from using the same techniques and thinking to build applications across both web and mobile.
While we're certainly excited about what React Native represents, its worth noting that it may not be an ideal choice in all situations. It's great for straightforward data-driven applications, but likely not an ideal choice when you need highly customized UI elements, interactions, animations, hardware-access, etc.
Much of the native platform is exposed via React Natives core components, but not everything. For example, with React Native you have access to vibration functionality on both platforms, but it is currently not possible to create a vibration pattern. That said, while you may hit some limitations like this, it is possible to build custom wrapper components to access more of the native platform functionality, so it is not an all-or-nothing proposition.
React Native is a novel approach to building mobile applications using JavaScript and web technology. It's certainly not the first, with platforms like Phonegap and Cordova having paved the way. Those frameworks took a different approach in which they wrap a native frame around a webview, and then run a web (HTML, CSS, and JS) application in the webview. This is referred to as a "hybrid" application.
React Native instead runs your application code in a background thread, executing your JavaScript and then sending layout commands to a main thread, calling into native platform APIs to build and arrange truly native UIs. User interactions are communicated from this main thread to the background thread where any updates to the UI are computed (using Reacts wonderful declarative virtual DOM magic) and then updates are communicated back to the main thread.
A nice feature of this is that all interactions are automatically handled off the main thread, which means that the UI remains responsive, even while handling more complex computation.
As discussed above, one of the core benefits of React Native is that it opens up the world of mobile application development to developers and designers who historically had focused on the web. By bringing a common approach to both platforms, we now have a common way to build applications.
Another great benefit of React Native is code reuse across the various versions of an application. In a post discussing the process of building the Android version of their mobile ad manger (for which they had already built a React Native iOS version), Facebook shared that they were able to reuse ~85% of the code across the two platforms. That sounds like a nearly ideal ratio. Re-use the vast majority, but still allow for customizing that last ~15% to ensure solid integration and alignment with native platform interactions.
Lastly, since React Native is using JavaScript to run the application, there is no longer a need to continually re-compile the application with each change. In fact, with each release React Native improves the development workflow with steps like removing the need to open Xcode, supporting live reloading, and the recent addition of support for hot reloading.
To dive in a bit deeper, we'll take a look at a very simple React Native app that displays three boxes, and allows the user to hide or show the boxes by pressing a button.
We can run the application with two commands:
# start the JS file watcher process to
# build and bundle the application code
$ react-native start
# start the iOS simulator to interact
# with out application
$ react-native run-ios
To start, we'll take a look at the main component of the application:
import React, {
AppRegistry,
Component,
StyleSheet,
Text,
View,
TouchableHighlight
} from 'react-native';
class WeeklyIterationDemo extends React.Component {
constructor(props) {
super(props)
this.state = {
boxesHidden: false,
}
}
toggleBoxes() {
console.log(this.state)
this.setState({
boxesHidden: !this.state.boxesHidden
})
}
renderBoxes() {
if (this.state.boxesHidden) {
return (
<View style={styles.boxesContainer}>
<View styles={styles.box} />
<View styles={styles.box} />
<View styles={styles.box} />
</View>
)
} else {
return null;
}
}
render() {
var buttonText = this.state.boxesHidden ? "Show" : "Hide";
return (
<View style={styles.container}>
<TouchableHighlight onPress{() => this.toggleBoxes()} style={styles.button}>
<Text style={styles.buttonText}>{buttonText} boxes</Text>
</TouchableHighlight>
{this.renderBoxes()}
</View>
);
}
}
To highlight a few of the interesting features at play in this example:
import
- import
is a part of ES6 (check out
our Weekly Iteration episode on ES6), but the nice thing is React
Native handles all the compilation for youReact native includes support for flexbox style declarations, and will automatically convert those flexbox styles into the platform specific variant. Flexbox was a very welcome addition to the world of web design, making it drastically easier to build and style applications. The mobile world benefits perhaps even more so from the ability to use flexbox as the native platform layout and styling functionality is an often highlighted as being difficult to work with.
Check out our Weekly Iteration episode on Flexbox if you need a refresher.
Another area where web developers will feel at home is that React Native
allows us to use the Chrome Developer Tools for debugging. console.log
and even debugger
statements will just work, which makes building and
debugging React Native applications very approachable for those new to the
platform.
From its initial release, React Native has had a great story around rapid iteration and feedback cycles thanks to not needing to compile. It took things a step further with the addition of live reloading where the simulator would automatically reload the application when a file was updated. And now, with the addition of hot reloading, they've taken things to the next level.
With hot reloading, each time you save a component, the live code running in
the simulator will update while maintaining the application state like the
current view or the boxesHidden
property in our demo. This may not read as
that amazing, but in practice hot reloading can totally change the way in
which we build applications, making tiny changes and immediately getting
feedback.
Now we can dive a little deeper and take a look at an application the targets both Android and iOS from a single codebase.
The majority of components available on React Native will abstract away the differences between the platforms. In this application, all but one of the components used will work on either platform without our code needing to handle the distinctions at all.
Looking at the code used, we can see that we're using the Navigator
, ListView
,
Text
, and View
components, all without needing to worry about platform
distinctions.
The only component in our application that has platform specific
implementations is our Button
component. The nice thing is that React Native
makes it very easy to opt into platform specific versions of components by
simply naming the files with a platform specific file extension:
// button.ios.js file
import React, {
TouchableHighlight
} from 'react-native'
export default class Button extends React.Component {
render() {
return <TouchableHighlight {...this.props} underlayColor={'#eee'} />
}
}
import React, {
TouchableNativeFeedback
} from 'react-native'
export default class Button extends React.Component {
render() {
return <TouchableNativeFeedback {...this.props} />
}
}
Between the two, we can see that the only difference is in the touch specific implementation for Android vs iOS. With these two files defined, the code that uses this component can now be blissfully unaware of the platform distinctions, and simply import and use the component like any other.
import React, {
StyleSheet,
Text,
View,
} from 'react-native'
import Button from './button'
import Quote from './quote'
export default class Row extends React.Component {
// ... other functions omitted
render() {
return (
<View>
<Button onPress={this.navigateTo.bind(this)}>
<View style={styles.rowContainer}>
<Text style={styles.text} numberOfLines={1}>{this.truncatedQuote()}</Text>
</View>
</Button>
</View>
)
}
}
The children
are passed as a prop
to our Button
component, allowing us
to define the platform specific implementation only where needed, and then use
it via the abstracted component we've created. Nice!
While React starting as a project for building web applications, it very quickly was ported to a whole variety of platforms including canvas, server rendering, and even custom implementations like Netflix's Gibbon system which allows them to render React applications on a whole variety of embedded TV systems.
Not with React Native, we can target Android and iOS, but the momentum is only growing with Microsoft recently announcing React Native on the Universal Windows Platform. There is even a React Native for the Web project (which is not a joke, much as it sounds like one). This speaks to the power of the abstractions introduced by React, and the value of the "learn once, write anywhere" philosophy.
If you're interested in giving React Native a shot, the best place to start is the projects own Getting Started guide.