Moving From React to React Native
8 min read
I’ve gone full circle and have recently gone back to developing for the web in my day job with React, after working with React Native for a year. Making the mindset shift from React to React Native, and now going back to React is not hard, but can be made significantly easier if an engineer goes into a move clearly knowing what the key similarities and differences are.
With React Native still fresh in my mind, and as I’m easing back into React for web, I wanted to write this blog post, as this is what I wish I had read, before starting React Native for the first time a year ago. I wrote a blog post with my initial thoughts, way back when I first started with React Native, but this is a more fleshed out version.
But first...
For those who have a limited idea about what React or React Native is, the main thing to understand is that React for web is an abstracted “framework” that renders down to HTML, which enables it to be read by a browser. React Native is specifically used to develop native apps (the common ones being iOS and Android) and thus renders down to native mobile elements (which differs for the various platforms). This means that React for web is designed to be run in a browser environment, versus React Native which is executed in a JS runtime, from within a native application.
Whilst there’s enough common ground to enable developers to move from one to the other without too much friction, this does also mean that there are some very specific ways that React Native works, which will require a bit of a mindset shift when coming from web. I’ll start first by laying down the similarities, before covering the differences below.
Similarities
Use of the React framework
- The most obvious one - whilst React Native is an abstracted framework for ultimately, mobile native platforms, it does still utilise React as a UI framework. This means that most of what you already understand around how React works, like component lifecycles, hooks and JSX transfers across.
- Following on from the point above, the fact that React Native uses React means that as a developer, you’ll be writing in JavaScript (or Typescript). You likely won’t need to delve into Swift or Kotlin, unless you’re having to deal with a specific native issue, or are having to develop features that React Native doesn’t yet bridge. (Saying that, it is helpful to be able to understand these languages, especially when it comes to bug fixing and troubleshooting!)
JavaScript eco-system
- The other nice thing about developing with JS, is that you get to plug into the vibrant and massive JS eco-system. Granted, you won’t be able to utilise packages that rely on browser DOMs or browser APIs, but there are still a lot of other useful packages and tools you’ll already know. This includes libraries like React Query and Redux, and also dev tools like ESLint, Prettier and Jest.
- If you’re interested, the reason this works is because React Native utilises a JS-bundler called Metro, which bundles up the application logic into a JS bundle. This is also what allows us to use fast refresh when developing at the JavaScript level.
- One thing to note with testing however, is that test runners and packages generally run with Node. Your React Native app will likely include, not just JS, but also native dependencies. You’ll therefore need to mock out your native dependencies when writing your tests with these JS-based testing libraries. This can be painful to say the least, and can make writing automated and end-to-end tests difficult. Testing React Native apps can therefore be a very manual process.
Differences
Runtime environment
- The main one off the bat, that a new React Native developer will notice are the primitive elements you use in your JSX. There’re no such things as
<div>
,<p>
and<img>
tags as these are HTML elements for the browser. What you’ll see instead are<View>
,<Text>
and<Image>
elements. Note that these are then further rendered down to native specific elements for iOS and Android. - Following on from this, because we’re not running in a browser environment when using React Native, you won’t have access to browser APIs and the browser DOM. This means you won’t see event handlers like
onClick
oronMouseOver
...which makes sense because the user will not be using a mouse when interacting with your mobile app, but instead (more likely than not), their finger. You’ll instead be dealing withonPress
oronLongPress
and other native gestures. - While you might miss out on browser APIs, you’ll gain by having access to mobile specific features like accelerometer, screen view modes and haptic touch. ✌️
- The other big area to be aware of is how animations are programmed. With React for web, this can be done via CSS. With React Native, you’ll need to do this with the Animated API or an external package like Reanimated. Note that performance is something you want to be cognisant about when using animations in React Native, as these are determined in the JavaScript thread, but needs to be communicated to the native UI thread which can gum things up.
Styling
- This was probably the most annoying one to get to grips with as it requires a shift in thinking that I wasn’t really aware of. The main thing to know is that styling on React Native does not use CSS. It instead uses a styling API which utilises something akin to inline styling, where you pass styles (via objects) directly into the individual React Native elements.
- There is no cascading of styles in React Native! There’s also no such thing as selectors or nesting!
- This means that on the one hand, it feels incredibly manual and archaic when you first come across styling on RN. However, once it becomes second nature, it’s actually really nice in its simplicity as you never really have to deal with weird styles appearing from seemingly nowhere, higher up in the styling cascade.
- The one thing that is the same, is that both React for web and React Native uses the idea of a flexbox. The default
flex-direction
in React Native iscolumn
, rather thanrow
in CSS. The defaultdisplay
setting in React Native isflex
, so you don’t need to explicitly declare this.
Navigation
- The main mental model shift is to think of “screens” in React Native, being ordered in a stack. Each new screen you navigate to means you’re adding a new screen on top of your stack. If you navigate backwards, you’re popping that screen off the stack.
- The other main thing to note is the use of URLs. In a web browser, you’re able to use URLs for navigation (making a specific server call to get HTML, which in turn pulls in CSS and JS). In mobile apps however, you’re not able to use a URL to navigate to a specific screen. (You can still use URLs behind the scenes to grab resources like images on the fly though.)
- URLs in the browser can also represent a navigational state within the web app (e.g. you can refresh the page and have the navigation state persist). This is not the usual behaviour in React Native apps, whereby refreshing the app will not persist navigation state by default.
- React Native has third-party packages that help with navigation, with a very common one being React Navigation.
Deployment process
- Not going to lie, this is the part that I like the least about React Native, or more specifically, developing for mobile. Deployment of web apps is so easy nowadays. You can literally code up an app and deploy it for the entire world to see in under 10 minutes. Not so with mobile apps.
- The 2 main mobile operating systems are iOS and Android. Mobile apps for these platforms are distributed through the Apple App Store and Google Play Store respectively. You’ll therefore need to go through a review and approval process if you want to get your app listed on these stores, and these obviously will be two completely separate application processes.
- You’ll also need to go through this process every time you issue a native update to your app. You can release JavaScript-only updates via the Over-The-Air mechanism (OTA), which by-passes the app stores approval processes, making it infinitely simpler. Your users will get these updates whenever they reload the app (i.e. when the JavaScript bundle is updated).
- The deployment process is made more complicated if you also want to distribute a staging or beta app to app testers for QA testing before distributing to the app store. For this, you’ll likely want to use something like Firebase or AppCenter to distribute apps to a private testing group. You’ll therefore need to build different versions of your app, but also need to manage signing certificates for your iOS app to ensure this can be distributed. Fastlane is a tool that can help with managing this.
So that’s everything on my list that I can think of right now. If I’m missing anything, let me know, and I’ll add it to this list. 🙃