A Place for React Native

React Native might be best left to building particularly complex user interfaces within an existing native application; not necessarily as a complete replacement for native development.

As background, I have been a web developer for as long as there has been the web; most recently using React + Redux for about two years (am an AngularJS refugee). At the same time, I have been in and out of Android development since its inception in 2008. Never warmed up to IOS development; partially because I was too cheap to buy Apple hardware and Objective-C just felt weird.

Wanting to leverage my web skills in building mobile applications for both Android and IOS, I have tried a number of solutions: web with HTML5 application cache, PhoneGap, Apache Cordova, and most recently dabbling with React Native. I bought into the primary argument for using these sorts of solutions:

Learn once, write anywhere: Build mobile apps with React

React Native

At the same time, it has always been challenging to make these solutions look and feel like a true native application; the native APIs are very rich and many are not available through these solutions. For a simple example, Android and IOS provide a simple to use Drag and Drop API that is not available through React Native.

Another problem, specific to React Native, is that you quickly find yourself fighting differences between how things behave (including some completely different components) between Android and IOS. For example, in my first bit of code in React Native, I found I had to account for the status bar on Android.

const styles = StyleSheet.create({
root: {
flex: 1,
marginTop: Platform.OS === 'ios' ? 0 : StatusBar.currentHeight,

I pretty quickly concluded that the first thing I would need to do is write two separate React Native applications to support the two platforms: Android and IOS. What?

My thinking is that managing the differences between the platforms in a single application is going to be too messy; lots of conditionals. The good news, however, is that they can share much of the same state management, e.g., Redux, code.

In the back of my mind, I had a sense that there was another argument, other than some shared code, for using React Native. Through an exercise of building a simple validated form in both native (Android) and React Native, I was reminded how powerful reactive programming techniques are. Thought to explain this concept through three versions of the simple validated form application.

Plain Forms

The first example is an Android application with no third-party libraries.

There are three text inputs for a first name, last name, and email. There is a button to submit the information. Information is required for all three inputs and the email must have a valid format. The button is disabled until all three inputs are filled in.

The guts of the functionality consists of code responding to value and focus changes of the inputs. For example, the following code responds to changes in the value of inputs by setting an error (if necessary). It also disables the submit button if any of the inputs have an error.


switch(editText.getId()) {
case R.id.activity_main__txt_first:
if (mFirstFieldDirty && s.toString().trim().equals("")) {
} else {
if (
mFirstField.getText().toString().trim().equals("") ||
mLastField.getText().toString().trim().equals("") ||
) {
} else {

The key observation is that the application state, e.g., input error, is stored in the elements themselves and the code imperatively sets that state. This is much like web development about ten years ago; derisively referred to as jQuery spaghetti code.

note: While this code could be somewhat improved on, e.g., further collapsing repetitive code, this approach would still be fundamentally imperative.

While this particular example is fairly simple, the big challenge with this approach is that it becomes exponentially brittle (breakable code) as the complexity grows.

Facebook provides a more complete explanation of the challenges and solutions around building complex (user facing) applications.

Library Forms

Thinking that there had to be a better solution, I researched if there were Android libraries that simplify form management. The one that repeatedly came up was android-saripaar.

This second example has the same functionality as the first; just implemented an Android application with the android-saripaar library. While the resultant code is significantly shorter and easier to maintain, it still essentially shares the same imperative approach as our first example; in the end the state is stored in the elements and managed imperatively as we see below:


@NotEmpty(message = "Required")
private EditText mFirstField;
@NotEmpty(message = "Required")
private EditText mLastField;
@Email(message = "Valid Email Required")
private EditText mEmailField;
public void onValidationSucceeded() {
public void onValidationFailed(List<ValidationError> errors) {
for (ValidationError error : errors) {
View view = error.getView();
String message = error.getCollatedErrorMessage(this);
if (view instanceof EditText) {
switch(view.getId()) {
case R.id.activity_main__txt_first:
if (mFirstFieldDirty)
((EditText) view).setError(message);
public void onTextChanged(CharSequence s, int start, int before, int count) {
public void onFocusChange(View view, boolean hasFocus) {
if (hasFocus) return;

React Forms

The third example demonstrates a completely different, reactive programming, technique using React Native. It has the exact same functionality as the first two examples.

note: Interestingly enough, React Native does not support Material Design on Android; leaving it to you to style elements or use use third-party libraries.

This example uses both Redux (state management) and Redux Form (form state management on top of Redux).

As you can see from the code below, never do you imperatively set the error state of an element. Instead, you provide the conditions on which an element will have an error, e.g., the required function on the firstName element. Then, as the user interacts with an element, the error and touched property are passed to the input, i.e., ValidatedInput, to be used to conditionally display the error.

Likewise, the form is provided both a submitting and valid property that we can use to conditionally disable the Submit button element. Again, never do we imperatively disable the element.


const required = value => (value ? undefined : 'Required');
<View style={styles.root}>
<ScrollView style={styles.rootScroll}>
props={{ placeholder: 'First Name' }}
disabled={submitting || !valid}


{error !== null && touched && <Text>{error}</Text>}


I started writing this article with a bias to conclude that using React Native would rapidly speed up the development of native apps. My original assumption, like others, was that the benefit was in being able to build both an Android and IOS application from a single React Native project.

Quickly after using React Native, I decided that I should split up the code into two React Native projects (Android and IOS) instead of conditionally managing the large number differences between them. I then was satisfied with the idea that at least the data management elements of the project would be shared between them.

However, reflecting on all the missing native API elements, e.g., Drag and Drop API, I started to question using React Native at all.

On the flip side, I thought about the difficulty of building a complex user interface without using reactive programming techniques (as illustrated by the simple form example).

My conclusion is that it is likely best to begin development of the native applications using the traditional native development environments. You, however, might use React Native (with reactive programming techniques) for some portions of the application with a particularly complex user interface.

At the same time, I am separately exploring using the Reactive Extensions libraries as a way to do reactive programming techniques directly in the native development environment.

Working on that article…