How We Save Our Clients Money Building Cross-Platform Apps With React
React Native has become increasingly popular since its initial release in 2015, and it’s easy to see why. It’s become a well-supported, well-maintained solution to building cross-platform apps, and I’ve spent most of my time doing just that with the team at Input Logic. Before using React Native at Input Logic, we produced all our mobile applications through native code — Swift, Kotlin, Java — and while native applications are still a perfect solution in many instances, React Native has allowed us to ship cross-platform apps for clients for around 60% of the cost of going pure native. It’s helped me to provide clients with solutions that perform well and cut down our development time — which make a big difference for our team and our clients.
In this post, I’ll share some of my experience and tips for using React Native to help you figure out if it’s right for your next project.
Why React Native?
If you have a project or a business — especially a startup — React Native is a great way to get everything up-and-running quickly. It’s a fantastic tool for rapid prototyping, due to the nature of how React works — everything is designed in components, and with a single update to a component, you can see changes reflected across every screen in your app. You can develop applications for multiple platforms that share the same code base, and you get to skip out on some of the more tedious native code that differs between iOS and Android. As a developer, you don’t have to face the monotonous task of constantly rebuilding your application to see changes, with React Native’s hot reloading feature providing quick — almost instant — feedback as you build out your features.
Looking past the time-saving benefits, it’s important to note that you can build React Native apps with basically every feature that would be offered in a native application. I’ve either tested or implemented push notifications, geo-fencing, messaging, analytics, event tracking, biometrics authentication, offline modes, and social login, just to name a few. Apps that we’ve built or worked on at Input have also been met with largely positive feedback from users, showing ratings higher than ⅘ stars for each, with minimal complaints or crashes.
Before You Start
Is React Native right for your project?
While there are a number of benefits to using React Native for most applications, there are always cases where it just makes more sense to build a regular native app. Before deciding what’s going to work for you, it may be beneficial to ask yourself the following questions:
- Do I need any resource-heavy or complex 3rd party tools or SDKs?
- Do I need to develop for both Android and iOS?
- How many native features do I need?
Based off of how you answer these questions, you can start to get an idea of whether it makes more sense for you to build an app natively or if you should move forward with React Native.
For example, as a developer, if you need a feature-rich application where you’re going to have to code a multitude of native features just to work with React Native, your time may be better spent building everything natively.
React Native != Web
- While styling does have a camel-case CSS syntax, in many instances it won’t behave as it does on the web.
- Animation is not handled through transforms or keyframes, but rather an API which behaves much differently
- Shadows are implemented differently
- Media queries do not exist
- Flexbox only
Understanding Native Development
Going through a project without ever having to touch native code is highly unlikely, and at some point you’re going to have to use it.
While you don’t have to be an expert in these native programming languages, you should have a basic understanding of how each platform works. Be prepared to add tablet support, splash screens or other things you may not think you need right now, but may in the future due to changes in circumstance, scope, or feedback.
It’s also very valuable to learn how React Native module linking works. Often, it’s handy to know not only how to manually link a native module, but how to build, edit, and bridge native code if you need to. There will inevitably come a time when a client wants to use a 3rd party tool, and that tool does not have a React Native wrapper.
Advice From My Experience
Just like with React, React Native projects can be built in a wide variety of ways. I’m not here to tell you what works best, as this is largely based on how your team works together. Find a way to build things your whole team can get on board with, and stick to it. Keep things clear, and standardize your approach throughout your app. Keep in mind that boilerplate or auto-generated skeleton projects sometimes come with extra complexity you might not need or may be confusing as you move through your project.
Use the APIs, Luke
React Native is filled with built-in functionality and features out of the box, and it’s important to check what is available to you through the API.
The Platform API can help you with Platform specific code, as can the global `__DEV__` variable. Even text input components have helpful properties like character limit, keyboard appearance, and a host of other things that you might not notice until you read the documentation.
There are also a wide-variety of features outside the UI so it’s worth checking out the docs before you decide to go build your own functionality.
Upgrading React Native
Upgrading React Native can be taxing if left for too long, and sometimes the solutions provided just don’t seem to work, have too many conflicts, and can cause you a world of pain.
I’ve found the best approach to updates is to do them incrementally, based on what was changed from version-to-version. At Input, we often reference rn-diff so we know what to expect, while using npm-check-updates for updating our node modules. It’s also helpful to check the changelog between versions to see what improvements or new standards have been set forth (ex. upgrading from List to FlatList).
Versioning and Data Persistence
If you’re using something to persist your application state like redux-persist, use semantic versioning, or a method of determining whether persisted data is compatible with your new app version, and have some kind of fallback in the event it’s not. While your application may not crash in development after changing your state object, or whatever data you’ve chosen to persist, a user who is multiple versions behind and chooses to update their app may not have the same experience.
This is probably one of biggest issues people face when dealing with React Native. I’ve had the chance to use multiple different navigation libraries, and up to this point feel as though react-navigation is the most suitable to my needs. It’s important to plan out how to organize your navigators, and be mindful of what components are being mounted and when. Too many nested navigators can result in many screen components being mounted at the same time, and it’s possible that you can run into memory issues if you’ve got things running in the background.
Libraries for React Native
I’ve found a few libraries helpful after exploring and testing different options. Below is a list of options I’ve found advantageous to my workflow, and why I chose them.
react-native-firebase — There are a few options out there for dealing with mobile push notifications, but I found this library to be the simplest to use. I’ve had to use other 3rd party solutions upon client request, but they all used firebase in one way or another for Android notifications. Using firebase as a solution for both platforms takes out a few extra steps, and reduces complexity.
tipsi-stripe — This is a great choice if your app uses or receives payments with stripe. It’s easy setup, and has built-in interfaces for handling credit card information if you don’t want to code your own screens and validation. You also have access to G pay and Apple Pay, and the library has improved greatly over the past year or so.
date-fns — Simple, and lightweight compared to some of the other date libraries out there.
react-native-svg — A great library for using SVGs in your app, and was especially helpful when implementing custom map markers with react-native-maps.
- Be careful with performing side effects in component lifecycle methods, as large tasks can cause slowdowns in your app.
- Watch out for outdated advice or articles written about React Native. The framework has evolved rapidly over the last few years and the solution may no longer be accurate.
- Build both platforms at the same time, test on both frequently — Styling isn’t perfect between each platform, and there will be differences in positioning, text size, etc. Occasionally there can be differences in the JS core which may cause unwanted behavior on one platform.
- Test on physical devices, emulators don’t always behave the same as an actual phone, and some features may not even be available.
Overall, my experience has been overwhelmingly positive with React Native, and I’ll likely continue to use it for future projects. It provides a substantial amount of built-in functionality, and once you’ve established a workflow, and your team has developed a solid understanding on how to approach new features and functionality, it can be a very effective way to build highly successful and polished mobile applications.