Web to Mobile with React Native: Part II
Continued from an earlier blog post: ‘Web to Mobile with React Native’
With our prior experience of using React on the web, we decided to use React Native at KOMODO to build a complex proof-of-concept application for an insurance startup.
Where React Native really wins is the speed at which a developer without no knowledge of building native apps can get an application up and running. Normally there’s a difficult learning curve when it comes to developing on an unfamiliar platform, but React Native took that away completely. React Native UI components have most of the same styling options as a component on a web page.
Where React Native also stood out was in the documentation available. React’s documentation is very good, and there are hundreds of tutorials and examples available on both the official blog for the React project and from the community of interesting developers that have grown up around the React ecosystem. Most of these tutorials apply equally well to React and React Native, so even when there isn’t a native example available a developer can keep going.
Another great aspect of using React Native was the number of helper libraries and applications that are being built to enable developers to move even faster. The “create react native app” command-line utility has been extended to include adding routes, services and generators to an app with a simple command. We tried React Native Ignite and found it to be especially useful at the beginning.
Using plugins to access maps and photos proved reasonably straightforward too. Much of the early experimentation we did with the framework ‘just works’, so we were enthusiastic to move on with the proof of concept application.
Our first challenge with React Native
While React Native is very close to the way things are written for the web it’s not *exactly* the same. This meant there were some pitfalls that we fell into at the beginning. The first was that the Yoga layout library that React Native uses to emulate CSS and Flexbox doesn’t implement things in ways a web developer would expect. A <Text> element in React Native modifies its behaviour to be block or inline style depending on whether or not it’s wrapped in a <View> element (most things end up in <View>s). This isn’t a show-stopping problem at all, but it’s incredibly annoying when all of the documentation claims web-like capabilities.
The next problem was that we found plugins, while often very good, sometimes seemed like they only implemented an iOS or an Android interaction style. This meant that on one platform or the other the way things worked wasn’t quite the same as a native app, which users weren’t always very happy about. In our proof of concept application, this was a very minor problem, but in the final production build, it means spending time making things work everywhere. Writing cross-platform code doesn’t necessarily mean writing things once.
The next hurdle for developing mobile apps with web technologies was actually nothing to do with the technology itself. The way that a web application, particularly a single page app, works is *very* different to a mobile application. We attempted to write our proof of concept as if it was a web app running on a phone, and that really didn’t work at all.
In a mobile application, the UX is generally that there should be one page in the app for each significant feature. In a web application, things are often grouped together so a part of the covers several different logical features. React Native lets a developer write an application in the ‘web style’, but it starts to fail as more pages are added and things don’t feel quite ‘mobile style’ enough. This was a problem especially around the modal input forms (where a user interacting with a button should bring up a form). In a web app that modal would always be a part of the page; in a mobile application, it’s a separate page with its own routing.
Another problem was the handling of what happens when a user doesn’t have a connection to the internet. In web development this is handled well by the browser itself – page loads give a friendly error, and background requests are promise-driven which makes them easy to catch. In a mobile application, the app itself can crash and take the user back to their home screen if the internet connection fails. This has to be handled properly or the user’s experience is horrible. That wasn’t something obvious to start with.
This would have been less of a problem on a larger team with native application developers working alongside a web developer, or if the design team was experienced enough in native design to indicate how pages should work, but as this was a proof of concept that wasn’t the case for our test.
All of these issues were quite trivial in the grand scheme of the project. They were overcome easily, and the project always had good forward momentum. They could have been avoided, but that’s something that only became obvious with hindsight.
Testing, debugging and performance optimisation
Where React Native really fell down was in the tools available for testing, debugging and performance optimisation.
By default React Native will attach to a remote Chrome DevTools console for debugging. This is extraordinarily limited, providing a developer with little more than a log function. For any experienced web developer, this is a giant step backwards from the development experience we’re used to.
There are better tools available. React-native-debugger wraps the DevTools console, a DOM tree viewer, and a Redux state manager together in a single app that a React Native app can attach to in place of the Chrome window. This is better, not least because it enables a developer to actually inspect what’s happening in the page to fix layout issues, but it still isn’t as good a proper step-through debugging process.
There were other aspects of the build process that were more problematic, and really things that needed an experienced mobile developer to resolve. For example, the React Native linker, which informs the iOS and Android build tools which plugins are used in the app, isn’t idempotent. In other words, running it twice can break the application’s build files. This is a problem on a team where multiple developers are working on the codebase at the same time.
Sign up to our newsletter
Be the first to hear about our events, industry insights and what’s going on at Komodo. We promise we’ll respect your inbox and only send you stuff we’d actually read ourselves.