React-native first impressions: Expo vs. Native

paulsc
5 min readSep 11, 2017

I recently made my first foray into React-native, while trying to port motogo to Android. Motogo is an app that lets motorcycle riders find fun curvy roads to ride on.

It does this by crawling through OpenStreetMaps data for every road in your area, and calculates a curvature index (thanks to Adam Franco), and some other things, to find the best roads.

After dragging my feet for a while, I decided to build a basic Android clone of the app. The idea is to eventually be able to fully replace the native iOS version once feature parity is reached, and then just work on one codebase.

Getting started was a little painful. Some pain is to be expected when starting with any new framework. However, a lot of confusion came out of react’s dual Expo / CRNA & Native system. React native has two distinct environments that you can build and run your apps in.

Here’s my take on getting started with react-native, maybe this is useful to someone giving it a spin.

Exponent

Expo apps are the first thing featured on the Getting Started guide and get created using create-react-native-app (a.k.a. CRNA). Expo holds your hand little bit more but has a limited set of components that you can work with. It’s meant to get you started quicker.

To use Expo you have to first download their ‘host’ app, which your app will run inside of. Expo has it’s own app store and way to distribute apps to your friends ands colleagues. However you can also create independent apps for the respective app stores. One of the cool features is that you can build an iOS app in the cloud without owning a mac. The service is currently marked as Beta for the iOS platform.

The Expo ‘host app’

Expo projects also have a different file structure, most notably there are no iOS or Android folders at all, it’s 100% javascript. This means you cannot do your own builds without doing something called ‘ejecting’.

Native Code a.k.a. ejecting

The alternative is known in the Getting Started guide as “Native Code”. The naming is a little confusing to me as it implies writing Java or Swift code which is not the case.

These projects are created with react-native init and the folder structure contains two actual iOS and Android projects that can be built with the Xcode / Android Studio if you choose. Or you can run the projects from the command line, and still benefit of some of the neat little things like hot-reloading.

You still write all javascript, however here you have the option to go and dig into the native project in case you need to do something custom for one of the platforms.

Contrary to expo, you can use any of the many open source components that are available out there. This makes sense in retrospect; Expo apps run inside of a host app, and they can push updates independently of the app store. While this is neat, it also means you’re releasing code without doing a new build, so it’s impossible to insert new native code into the app. What gets updated is the main app-logic javascript code that interacts with the limited (but surely quite sufficient for a lot of apps) set of of Expo components.

Confusion

I wish I would have used “Native” from the get go, instead I wasted quite a bit of time with Expo. It took me a while to understand that there are two ways to do things and what all these terms like “ejecting” and “CRNA” mean.

Ejecting is when you have an Expo app, and you decide to go “Native”. This is a one time command-line conversion that you cannot reverse except by rolling back your code from version control.

If you decide to eject, you can use something called ExpoKit which will make all the Expo stuff available as a library and you won’t have to replace them all manually with Native components. Or you can go “full native”.

The root view of the app is a Google Maps component. I use Google Maps instead of Apple Maps for ease of styling and consistent look on both platforms.

Seeing your changes update in real-time on both iOS and android emulators is pretty cool.

I quickly found out that react-native-maps is what I’m looking for. It’s a map component open sourced by Airbnb, and it allows you to pick whether to use Apple Maps or Google Maps on iOS.

However I struggled to get going because I was trying to install this into an Expo app, which doesn’t support these external components. A tip that would’ve saved me a lot of time is that anything requiring a react native link command will not run on an Expo app. The link command will install your newly installed node package into the native projects, which is something that can only happen with “Native” projects.

Later I found out that Expo has it’s own Map component based on Airbnb’s component and it’s much easier to install. However I would still end up having to “eject” so that didn’t matter in the end.

Why go Native

  • Expo’s iOS build process is currently marked as beta.
  • I like the idea of having control over my own builds. Submitting an apk file that was built remotely makes me uneasy.
  • You can’t use any of the many native components out there. This is technically not a good reason as you could just wait until the need arises, and then eject if required. You might be fine with Expo’s components.
  • Maybe the biggest one for me is that the whole thing feels like adding another layer of indirection and complexity to an already complicated stack. E.g. Expo’s MapView is based upon Airbnb’s react-native-maps which is itself an amalgamation of a bunch of Native Maps components.

I wish Expo would get removed from the react-native Getting Started guide to avoid confusing new arrivals. At least it should be introduced in a more explicit way. For example it would make more sense if create-react-native-app was instead named create-expo-app, so that you get the intuition that you’re using a framework sitting on top of RN, and not the “standard” way of doing things.

That’s it for now, I hope this helps someone to get going. Stay tuned for more posts on react-native.

--

--