Introduction
As web developers, we see the potential that the web offers, as a platform and as a cross platform development environment. I don't think it's a desire for sameness or lack of imagination that propels web technologies across device targets, but the potential and power of what those tools can provide.
But being so ubiquitous means that solutions often fall short or feel off in comparison to what a platform provides natively. Native application development vs development using a web stack is a source of constant debate, and generally when tested at the extremes, web technology struggles to hold up to what a native experience can offer.
The gap is closing. Cordova has been a great environment, but as a baseline it is difficult to achieve the same level of polish and native feel that comes more natural from a native application. Frameworks like Ionic and Framework 7 make bridging that gap much easier. Their creators and developers have taken the time to polish and provide a set of tools, interactions and widgets so you don't have to try and build it from scratch every time (and often fall short in trying).
But what if we could utilize our familiarity with part of the web stack (javascript) to delivery something truly native? A seamless experience delivered by web tech but not bound by it.
React native might be the answer to doing just that.
Where I'm Coming From
Talking about React Native as someone who uses web technologies in almost all of my development, a meaningful comparison would reference back to that tech. When is and how is React Native more compelling than what the competition offers?
What makes it a better alternative to a tool like Cordova matched with Ionic or Framework7? What are its clear strengths? Where is it lacking and where will it improve? That's what i'm trying to answer for myself, and explore in the rest of this post.
A Very Brief History
React is the base library that powers React Native, and is a view layer, written in Javascript, and originally created by engineers at Facebook. Since its initial release in 2014 it has risen in popularity quickly (32K stars on github and rising) and people have been embracing its model. You write all of your view layer in their abstractions, and let them manage rendering to the appropriate format. They manage your UI and the flow of your data in an optimized way.
We're seeing them refine React into a reusable base library, and extract the view implementations into their own modules (they recently removed all DOM related logic and created a new package - react-dom
- to handle that for the web side of things). In addition to react-dom in the browser, people are using React for server-side rendering, and Flipboard recently came out with react-canvas - which writes your UI directly to the canvas tag. These are just a few examples of React view implementations taking the base React layer and applying it across different environments.
The obvious momentum here is towards reusing the React architecture to output to different formats. React Native takes these same principles, and applies it to the native app environment.
Why React Native
Learn Once, Write Anywhere
"The focus of React Native is on developer efficiency across all the platforms you care about — learn once, write anywhere." (https://facebook.github.io/react-native/)
With the ability to learn all of the react principles and patterns, and then apply those to whatever view abstraction can be written, you're able to take all of that knowledge and apply it on multiple views and across different platforms. Not just platforms that contain a browser but any platform where javascript can be run.
You know react from using it in other environments, and you're now able to leverage that to build a native app. The components are different, how it functions is different, but the concepts are all the same.
Truly native
Everything you use in React Native is, behind the scenes, a native UI component. Many of the features that native developers are accustomed to on Android and iOS are available to you in their actual forms.
My understanding is that React Native makes this possible by serializing communications from your Javascript layer to a native layer, where the UI work is accomplished. Your javascript SwitchIOS
component is a native iOS switch. Same for your MapView
and ListView
. It's all first-class with the rest of the app environment. You define what you want to use in Javascript, and React Native handles the communication and implementation of how it is rendered.
The result is a larger ecosystem of code you can lean on, as well as out of the box improved performance.
Performance
One of the top reasons to use React Native is for performance. Because your javascript is communicating instructions to actual native code, you are able to operate at near native speeds. Your animations, gesture recognition and layout rendering will all be faster with no additional effort on your part.
Knowing that you are getting these out of the box gains, the main concern you are left with is keeping your javascript code running lean. Javascript operations are batched up and then sent to the native layer, but if your processing takes too long you can miss some of those communication windows and cause visibly degraded performance.
The React Native's team is heavily focused on getting the best performance out of every aspect of the library they control. As part of their developer tools you can actually monitor the framerates of both your native UI and javascript threads, which helps to debug where a slowdown might be occurring.
First Class Native Projects + Keeping up with iOS/Android updates
With a React Native project your generated iOS and Android applications are a first-class part of your development and source control. The obvious benefit here is unobstructed control of all of your application settings and libraries.
In the Cordova model, your "platforms" (the implementation of code for a given operation system like iOS and Android) are read-only and are not intended to be source controlled. The output of that generated code is controlled from generic configuration files within your project.
The Cordova approach is a double edged sword because while you are benefiting from the generic cross-platform nature of your configuration files, you can also lag behind new developments and be forced to wait on Cordova updates or make modifications to the runtime yourself. Recently there were issues with the introduction of Application Transport Security in iOS 9, which meant having to use some hacks to get around the problem until Cordova could release an update to address it (which took some time).
Using React Native you trade off the generic configurability of Cordova for full project control.
Community
The React Native community is growing fast. Much like the React community, React Native is garnering tons of attention and contribution. As of this writing they have around 24k github stars, and new modules are coming out for it every week.
But,
It doesn't feel quite like an ecosystem yet as much as a large group of people excitedly producing code. There are a number of React Native modules started and abandoned, many of the modules are not mature enough yet, and they're working on a moving target. The React Native team is doing a good job avoiding massive breaking changes, but the framework is young and these things are to be expected.
App Reloads / Dev Tools
Ability to reload from the app was awesome, and something Cordova and Ionic are only just starting to offer.
You can bring up and options menu while running your application in real-time, and it comes with several options including live code reload, remote debugging from your browser, and performance statistics of your running code.
Touch Events
The gesture system in React Native is a rich and complicated aspect of the library. They claim that the touch interaction offered by the web is a big usability issue, and that "Users can feel huge differences in the usability of web apps vs. native" ref.
I've seen and worked with some great touch interactions in a web context - but I believe them that there is more the user could be offered. I just haven't seen the value in action yet. The "Gesture Responder System" is a fairly dense API and I haven't gone beyond basic tap interactions with it so far.
UI Flow
Everything being native, the flow and styling of your application is very consistent. Contrast this with trying to integrate a native component into a Cordova application and it's a very different experience. Bringing in something like the native Map component and trying to style it into a completely different UI paradigm (your webview) can be confusing and the precedence of elements unclear.
In React Native, it's as easy as laying out your components and styling them using a subset of CSS that you define in your javascript. The components interact and flow with each other naturally with no magic involved, because everything is speaking the same language.
Where it's the only option
One of the most interesting aspects of React Native is its ability to go places that standard web technologies cannot.
Up until a year ago, Cordova was still an option for all the common "smart" technologies that people used: phones and tablets for Android, iOS, Windows Phone (even Amazon FireOS, Firefox OS, Blackberry, and more). But it wasn't until the Apple Watch came out that hybrid developers found themselves at a loss. Watch OS 1 and Watch OS 2 do not support UIWebView.
Around six months later Apple released tvOS. Another platform intentionally missing UI and WKWebView.
There is a reasonable explanation for why they're excluding webviews: they just don't make sense on those platforms. The reason they include webviews is to be able to display web content. But interacting with a web page on your watch, even a responsive one, is cumbersome at best. tvOS has a similar problem in the opposite direction - they don't expect people to be interacting with webviews on a large screen using a remote control. Wired explains it pretty nicely: "Instead of tapping and swiping a 4.7-inch display with your fingers, you’re using a remote to control a 55-inch digital tapestry from 10 feet away. It’s like trying to play a banjo with two oven mitts on."
So without a webview, what can a hybrid developer do? The answer right now is nothing. So far there are no solutions to get around this problem.
So in the case of these two platforms, React Native has the potential to shine. Being a native technology that doesn't rely on a webview, we're able to adapt to almost any platform.
The community is already working on it for tvOS: https://github.com/facebook/react-native/issues/2618
Watch OS is not receiving much interest so far, but that certainly could change over the next year: https://github.com/facebook/react-native/issues/685
Unless Apple releases webview capabilities for these platforms in the future, Cordova will never be an option for them. So you're left with either developing something entirely natively, or using an environment like React Native.
Scratching the surface
There are alot of other reasons to look into React Native and what i've described are just my impressions, understanding and usage so far. Check out their docs for more. I haven't had a chance to fully utilize it yet, but their animation implementation looks powerful.
Why Cordova/Ionic
We've gone through what i've learned about React Native so far and what has me excited. But what are the positives to continuing with a tool like Cordova?
Familiarity
The obvious win for developing applications using standard web technologies is familiarity. When you develop an app using a tool like Cordova, you are writing standard HTML, CSS and Javascript. Whatever tools or approaches you add on top do not change the fact that this is the same code that could also power a website.
Does this familiarity actually play out in practice? Do web developers navigate seamlessly into the mobile world?
My experience is that no, it's rarely that straightforward or simple. Frameworks make it easier, but there is always a learning curve to thinking with a mobile mindset, understanding the proper interactions, and dealing with the quirks of developing in this environment.
But is the learning curve smaller - definitely.
CSS, not "Styles"
I glossed over the way React Native handles styling when I talked about UI Flows earlier. That's because despite the benefits of of all your components interacting consistently and performing nicely, the way you style them is not exciting. It works, but there are some definite weaknesses (you can read through a speaker deck about why they made these choices here. It's at the top of the article).
To start, what you know about CSS is only partially relevant here. The full specification is not implemented, shortcuts are not supported, and you have to define it all in your Javascript code. It's somewhat akin to writing all your styles using the dom style
attribute, but more limited (everything is assumed to be pixels, for instance, so you define things like margin and padding as simple integers).
For example:
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
margin: 10,
marginBottom: 5
},
text: {
color: 'black'
}
});
That code compiles your definition, and you can now use that styles
object to apply styling to your components.
Applying the styles
So how do we apply this to our components? Let's take a simple React Native code sample, and apply it to that. I'm not going to elaborate on what is going on in the code except to note how the styles are being applied, since the general concepts are the same as any React code.
var ExampleApp = React.createClass({
render: function() {
return (
<View style={styles.container}>
<Text style={styles.text}>
My example with styles applied.
</Text>
</View>
);
}
});
If you're like me, your initial reaction to that example is probably something like this:
It's a CSS styling sin to employ inline styling at all, let alone as your primary mechanism for your entire layout. It's a bummer, but in practice it's not so bad. In a sense the styles are acting a bit like selectors, in that you are defining your style elsewhere and referencing it from here. There is some amount of cascade that goes on here as well, though I haven't identified all the rules around it yet and have encountered some surprises along the way.
Flexing your layout
You may have noticed I have some flex properties defined in that example, and that's because in addition to only supporting a subset of properties, React Native only supports one layout option: Flexbox. This also seems like a downside, and technically it is (more options being better than less), but it turns out to be a pretty solid choice. Flexbox supports the app layout and concept nicely so in practice this is not a huge determent - just a learning curve for many developers (including myself).
Miscellaneous
There is no nesting of styles, so you end up defining multiple style objects, or prefacing your definitions with additional context about where it goes. It doesn't always use standard names and properties: flexDirection
instead of flex-flow
, for instance. So even where it is using standard CSS concepts there are some subtle differences. (correction).
React Native's approach to styling works, and at least you can take advantage of many of the principles of CSS... But it's not CSS. It's comparatively cumbersome, verbose, and seems likely to stay that way unless projects like react-native-css take off and become a community standard.
Back to Cordova
So developing using standard CSS means you have the full feature set of CSS available, and as new features are added you can start to take advantage of them immediately. It works the same way you're used to in your regular web development, and that's a pretty large advantage.
It also means you can potentially use things like CSS Grid Layouts. I'm going to back away slowly now, before i'm pressed further and you realize I have no idea why that would be useful to you. But it's coming, you won't get it with React Native today, and may never be able to.
Updating your app without updating your app
The app submission process is not known for being speedy, so having options to update application functionality without going through a full submission process is a definite benefit towards developing applications with Cordova. There are lots of tutorials explaining how you can achieve that, so I won't go into it here. But being able to load in your javascript and CSS remotely means faster code turnaround and faster deployment of new features to your users.
However
Originally I thought this would not be an option for React Native, but was proven wrong pretty quickly. It's not quite as straight forward as what you can do with Cordova, but there are approaches available.
Apphub offers a service for it: https://apphub.io/
And here is a medium article about dynamically updating your app: https://medium.com/ios-os-x-development/so-you-want-to-dynamically-update-your-react-native-app-d1d88bf11ede
Richer pre-built components
In fairness, React Native is a young library. And compared directly to straight Cordova, they actually have an advantage because of their out of the box native components.
But the existing pre-built components (both in the project and in the community) are still pretty limited at the moment, and not as mature as what you'd get by using a library like Ionic.
I was disappointed to find no Pull to Refresh or Swipe action implementations available in React Native itself. From what i've read in their responses to issues is that they aren't interested as a core project in coming up with a huge array of components - they want the community to get involved to build that out while they focus on the library itself. I can definitely respect that, and I look forward to what gets produced over the next year. There are already some community pull to refresh and swipe action implementations available, but the quality is variable right now.
So compared to what I can use now in Ionic, if I had to build something on a tight timeline and use a breadth of components, Ionic has a clear advantage.
Example
Before I close, there are a couple great tools I want to mention for playing around with React Native with the lowest barrier to entry possible.
Appetize.io (https://appetize.io/) is a service that lets you stream iOS and Android apps in the browser. While not directly relevant to React Native, it's what powers the next tool.
Rnplay.org let's you write React Native code in your browser and test it using their app viewer (which is powered by appetize.io). Other users can fork your code and for trying out React Native for the first time there is no better option (as long as you don't need to branch outside the core components). I've embedded an example here for you to try. Feel free to fork the code and see what you can put together!
https://rnplay.org/apps/aPx5Uw
Conclusion
You'll notice that where I have complaints about React Native, most of them are surface level, or related to the young age of the project. I'm excited about what React Native is offering, and excited for what is next for them.
I've been using Ionic/Cordova for awhile now, and really enjoy it. I've deployed client code using it, and will continue using it for the foreseeable future.
But React Native has definitely caught my eye, and I think it's a powerful and interesting project. It's not usable for everything just yet - there are some widget niceties that I think it needs for more mass appeal and quick use. But it will get there, and using it has been fun and productive so far.
I've got an app coming out soon that I will write about more in depth in terms of actual implementation details using React Native. Something very simple, but it gave me a good way to test the tech and see what React Native could offer and handle, and fueled everything in this post. I'll go into specifics about what modules I used, benefits of the native experience, issues I hit, community responsiveness, resources available, and bugs in the platform I encountered.
So what is my final feeling on React Native? Excited, and a little mixed. There's a side of me that loves everything they are offering and the possibilities, but it is also at odds with my love of a more pure web tech solution. Despite using many elements of web technology is also eschews a lot of it and does its own thing. So if you're a web developer looking to try React Native - you'll feel comfortable there, but not exactly at home.
Update 12/5/15:
Thanks to @notbrent for some feedback on this post. Notably pull to refresh just landed in core ios/android, and a mistake I made about non-standard flex properties (flex-direction
is valid. While react-native doesn't support shortcut definitions, the properties it supports should be capable of handling all simple forms in a standard way)