Mobile applications are an essential part of our tech stack here at Good Uncle. Our main consumer-facing storefront is an iOS app, and we also plan to build a suite of mobile applications to optimize our kitchen and delivery operations. When setting out to build these apps, React Native felt like a natural choice for a number of reasons.

This summer we completed the first version of our core iOS app, which was written entirely in JavaScript. Using React Native has been a tremendous success for our team. We place a huge emphasis on user experience, and React Native has empowered us with the tools to build an app that provides a great overall experience for our customers.

Through the spring, before development began, we had some doubts as to whether we could build a high-quality production application with with this nascent technology. First, was React Native mature and stable enough for a full scale consumer app? There were plenty of tutorials out there with examples of simple apps with a handful of views, but would we be able to build an app with several dozen views, a full onboarding and log-in flow, app settings, and payment processing? Additionally, we read all the claims promising 60fps rendering, but would it really offer us the flexibility to build a complex, responsive user interface? Our fantastic designers and UX Lead came up with a striking blueprint that called for many intricate UI elements, lots of animations, and subtle gesture inputs. We knew that React Native was more than suited to build applications that use "off the shelf" UI elements such as navigation controllers, tab bars, and table views, but could we use it to build an application with an entirely custom UI?

The answer to these questions is a resounding yes. As a team we are very proud of this app and are excited about how going forward we can use React Native to build out new features and refine the user experience further.

We have a lot to say about React Native and plan to share those reflections with you here over time. For now, however, we'd like to offer some high-level thoughts on React Native, having worked (and wrestled) with it for several months now.

The Good

A Fantastic Abstraction Layer

None of us at Good Uncle are expert iOS developers and I personally know just enough Cocoa Touch to be dangerous. (As an aside, building an application with React Native requires zero knowledge of traditional iOS frameworks, but in my experience it did help quite a bit to have a basic understating of what was going on "under the hood". It might be worth picking up a Big Nerd Ranch or other iOS development book if you are planning a major long-term project with React Native.) One criticism of Swift that I have heard repeatedly is that Apple perhaps missed an opportunity to move away from OOP and establish an entirely new paradigm for app development. For anyone turned off or fatigued by traditional iOS development you should look to React Native because it is fantastic. Period.

There are many reasons why React has become such a popular choice for front-end web development. Setting aside the performance and other benefits that are gained from use of the shadow DOM in the browser, what is great about React is that it makes your life easier as a developer, and the ways in which it does this for web development apply equally to mobile development. React allows us to write clean, concise code that is easy to reason about. As Facebook puts it, React is simple in that you "express how your app should look at any given point in time, and React will automatically manage all UI updates when your underlying data changes." The "magic" of the declarative nature of the framework is difficult to express in the abstract, but our firsthand experience (along with that of many other developers) is that React delivers on this promise. We are able to write code that allows us to easily understand how the UI will render based on the state of our data layer.

Most of the benefits of cleaner, concise code comes first from JSX, which requires a developer to combine her logic, layout, and styling in a single file. The syntax looks maddening at first, but combining all these elements in a single place makes for code that is orders of magnitude easier to write initially and maintain over time. Additionally, React's emphasis on separating an app's functionality into separate components allows for modular, well organized code. The developer has wide latitude to make these components as specific or general, large or small, as she pleases. A component could be a single button type, or an entire view.

The result of all this is that React enables you to build a complete app with a smaller code base in a short amount of time. It took a single developer just over seven weeks to build version 1.0 of our app. The code base for this first version was under 20,000 lines long and just over 10 MB.

Flexibility to Customize Views, Interactions, and Animations

As mentioned above, while we worried initially that React Native might be ill suited for the kinds of custom UI elements and interactions envisioned by our designers, those concerns quickly faded away once we had a chance to dive into the layout, animation, and gesture libraries built into React Native. Styling and laying out views is incredibly simple. Adding animations and event listeners is typically no more complicated than defining them in a simple helper function and attaching them to a view, text element, or image. It might take a bit of ingenuity to arrive at the layouts and interactions you desire, but I can say with tremendous confidence that with React Native it is possible to implement nearly anything you or your design team dreams up.

Hot Update

When we mention to other developers that we built our app with React Native, a common first response is: "You can do that hot update thing, right?" Yes, we can, we do, and it is great. For those who do not know, the App Store rules allow developers to update the executable JavaScript in their apps without going through the app review process. We plan to write an extensive post on how we have configured our deployment pipeline and app to handle hot updates, but in the meantime you should check out CodePush. We use CodePush and are fairly happy with it.

With hot update on, we can ship code to our iOS app every single day. We can bug fix on the fly and update the app on our own schedule to add new features for users. Once we merge a change to the production branch of our GitHub repo, our build pipeline kicks off, and within 5 minutes an updated version of our app is pushed to all our users. If this isn't using technology as a competitive advantage, I don't know what is.

Shared Code

Much of what has been written about sharing code in the context of React Native apps has focused on reusing JavaScript across a team's iOS and Android apps. Building an Android app is on the horizon for us. We're not there yet but when we do I hope to share our experience with code reuse. Still, having a mobile app written in JS has allowed us to share logic between the iOS app and our web apps. Many of the helper functions that were developed for our back-end web apps, such as those that help us sort, manipulate, and organize order information, delivery routes, and menu items, are fully portable to the iOS app, and vice-versa. This has saved us considerable development time and reinforced our decision to use JavaScript at every level of our stack.

Some Warnings Before Jumping In

Testing is Problematic

Right now, there is simply no way to write comprehensive unit tests for a React Native App of any considerable complexity. This was a bit of a disappointment for us, as a team that believes strongly in test driven development. Both the Enzyme and Jest communities seem to be working on providing better testing tools, but as of now too many core components have not been mocked out.

A partial solution that we rely on is automated UI tests, using a tool like Appium. Still, Appium is a bit cumbersome to set up and slow to run, and it won't necessarily test every corner of your logic layer.

Flexbox Won't Solve All Layout Problems

Many tutorials, videos, and blogs on React Native explain the benefits of flexbox to easily lay out views and handle multiple screen sizes. In our experience, flexbox has been very useful for layout, but it only gets you so far, especially if your app implements custom UI elements and views. If that is the case, expect to spend considerable time setting height, width, margin, padding, and placement properties for the three main iPhone screen sizes.

Limited Knowledge Base

React native right now is the wild west of mobile app development. It's an incredibly compelling technology that has attracted a lot of interest, but compared to a mature ecosystem like traditional iOS development, there is simply not a huge knowledge base out there. While a mobile developer working in Objective-C can probably find an answer to any question with a quick Google search, that is not the case with React Native. On top of this already scant knowledge base, React Native is moving fast and breaking changes are common, so the resources that are out there become outdated quickly.

If you are new to or considering working with React Native, be prepared to struggle. Be prepared to be led astray by a StackOverflow post that may have worked in July of 2015 but now causes your app to crash. Be prepared to follow a blog post explaining how to implement a bounce animation, only to discover that it breaks starting on the version of React Native released two prior to the one you are working with. Be prepared for Xcode to refuse to build your app with an error message that you will paste into Google, resulting in zero search hits.

More to Come

Over the coming weeks we plan to post here regularly to offer our perspective on the pros and cons of this new technology, explain how we solved some challenging problems, and talk a bit about what it is like to maintain and run a production application built on React Native. Check back soon.