I gave a talk at code.talks about building mobile applications with JavaScript.
Here are some of the slides from my talk.

Should I build a native app or use cross platform frameworks? There is no absolute answer to this question. The thing is that native development is fun and I personally prefer languages like Swift over JavaScript. The idea of writing my application once and being able to distribute it cross platform is still more interesting to me. I hope and bet that we will see web and mobile becoming unified in the future.

What is React Native

React Native is an open-source mobile application framework created by Facebook. It enables developers to write native mobile applications using JavaScript or TypeScript. Facebook is using the technology for products like Instagram, Facebook Marketplace and Facebook Ads Manager.

It’s a common misconception that React Native compiles JavaScript to native code. What it does is to provide a bridge abstraction for communication between JavaScript and native side. The native side consists of platform APIs, native core modules and custom modules.

JavaScript code executes on the JS thread and UI is being computed on the Main thread. This keeps the UI responsive to user interactions even when JavaScript is busy(most of the time). In extreme cases the Main thread could be occupied serializing the payload on the bridge. If the payload is large or has too high of a frequency then the UI can start to stutter.

There is an ongoing re-architecting of React Native known as Fabric. The new architecture will bring new features and performance improvements e.g.

  • Expose native objects to the JavaScript runtime using JSI instead of passing JSON data over the bridge
  • Fabric will allow user side effects e.g. touch events to be synchronous instead of asynchronous for faster response time.

The native side is exposed using the bridge interface that sends and receives JSON data. Here we are creating two UI elements. The invocation of these two components will send a message over the bridge to the native side.

The payload of the message contains a type 1 that indicates if the message are sent from JavaScript or type 0 if the message are sent from native. UIManager is the native module that is is responsible for creating and managing UI, the result of these requests will be to create the corresponding native element on the targeted platform e.g. UIView/UIText on iOS.

Product Development Experience

React Native targets both Android and iOS with one single codebase.

This allows teams to:

  • Cut down on developer costs and time by building for both platforms simultaneously
  • Increase consistency of the look and feel of UI
  • Sync releases of new features for both platforms

Product owners will thank you for not having to navigate between engineering departments(depending on how your organization is setup).

When you don’t have the need of native developers you can start bridging the gap between web and mobile. Sharing knowledge between web and mobile becomes easier. Leverage your organisations resources instead of hiring new engineers. I’ve seen engineers coming from a web background getting up to speed with React Native within a couple of days.

Since the cost of context switching between web and mobile becomes lower, you can start to build cross-functional teams where engineering and product are responsible for both web and mobile applications.

I would like to add that sharing code between web and mobile is also possible. I generally recommend to not share the UI part of the application since web and mobile have different primitives. I would rather focus on sharing the business logic.

The React Native eco system is mature. Combining the largest package repositories in the industry. Use popular JavaScript State management libraries or test runners of your choice like in any other React project. It’s a high chance that the UI your are indenting to build already exist as a component.

Many NPM libraries are anyways wrappers around native packages from CocoaPods or Gradle. If you don’t find what you are looking for and have some previous native developer experience. Then you can expose your own custom native module and wrap the library that you want to use. I’ve had to bridge two native module so far during my three years of experience using React Native.

With over 2k+ contributors the community is active and on top of issue handling. The project follows a monthly release cycle. Lately certain packages where moved out of the core of React native. This enables smaller initial bundle app size and invites the community to lead future improvements of core features.

The popularity of React Native is increasing. The fact that Facebook is dogfooding their own product makes us engineers have to worry less about future stabilities.

When developing you will have to initially compile your project to launch the app. If you have native changes you will have to recompile. Most of the time you will be developing on the JavaScript side and any changes will immediately be reflected. Instant feedback is a huge time saver that lets your developers iterate fast on building UI.

There is tricks to speed up development when building native apps. On iOS you can prototype your UI in storyboard for instant feedback or use the SwiftUI live preview feature. Still you will be re-compiling way more often when doing native development.

The React Native framework has a very low file size out of the box(depending on configurations). Because the framework is lightweight it can integrate with existing native application. One example would be to have “feature A” native and “feature B” as React Native.

To launch React Native from a native app is straight forward, you need to provide two things

  • Define the location for your JavaScript bundle(when developing locally, the JavaScript bundle is served on a localhost and on production the bundle is stored on the filesystem)
  • Render the React Native application in a view element. For iOS instantiate the RCTRootView class and assign the instance to the view of your view controller. On Android create an activity that extends from the ReactActivity class and then you can launch that activity as a new intent

Releasing new versions of your app can be frustrating. You need to wait for the app to be approved and released onto the store(especially true for iOS) and then you need to wait for users to actually update to the latest version.

Wire updates is a great feature and lets your team move fast. Since JavaScript can be served on the fly, you can use services such as CodePush and upload your JavaScript bundle to the Microsoft cloud and then distribute the bundle to all of your users devices. This lets you fix bugs or deploy features without releasing a new version through the stores. It brings “hot fixing” from web to mobile. If your app has native code changes you would still need to release as usual.

UI Paradigm

The first thing I tried to build natively on iOS and Android was something like a button and when the user pressed on it some text would change. It turned out to be quite different from how I usually reason and build my UI.

Imperative approach (iOS)

Disclaimer: This battle seems to have settled with SwiftUI coming to iOS and other “React” like libraries for Android.

These new UI paradigms is not yet an industry standard for native app development. If it becomes the standard then the transition from native to React would be even faster. Without using any third party libraries, out of the box for iOS it would look something like the example above. Android is a little bit different since you would declare your UI elements as XML and then bind the elements to your View class. The point I’m trying to make is that in React land, you never instantiate or bind objects and then mutate them.

Declarative approach (React)

This reads much better in my opinion. The render call might not look like JavaScript, React uses JSX to syntactically sugar function calls, It’s still JavaScript under the hood. It would be unfair to say that declarative API’s are better than imperative based on this comparison. With the concept of “children” in React and the declarative way of describing UI, composition do play very well.

React forces developers to build components that describes your UI. Part of designing components is to think about reusability and compose-ability. That is a superior paradigm in my experience of building UI. I’m happy to see other platforms adapting.

Reactivity
Here is two examples of how to update UI based on a user touch event.

iOS

iOS and Android achieves data binding via e.g. callbacks, delegation, notification, observables patterns to emit or observe UI changes. In the above example I’m directly mutating the “label” object to change the UI state.

React

React gives you a powerful reactivity model. The handleButton method when invoked will call the setState api and return a new copy of the state which will then re-render all child nodes in the UI tree(building a real application you will guard components for unnecessary re-renders). Data flows unidirectional(top to bottom). I used a class component in this example to demonstrate the analogy between native iOS and React components. React also lets you represent UI as plain functions.

React Native uses yoga engine which lets you use a subset of CSS, primarily the flex box model to position and style elements using JavaScript. Flex box gives you an API to specify a stack of elements on a x/y axis and how much space the elements should take up. You can specify the space between or around elements. It’s similar to stack view on iOS or linear layout on Android. The terminology differ, same principles.

Above example is trivial and proves the very basic of flex box and how it’s used to draw UI. The VeryNiceComponent is a function that takes children as argument and returns a view that positions the child elements in either row or a column. The Screen component invokes VeryNiceComponent with an array of children. Building UI with flex box on mobile is a very good fit. I never missed any other CSS properties.

No technology is perfect. There is always a tradeoff. Here’s a list of React Native the bad parts:

Not 100% JavaScript:

  • React Native requires native knowledge. The more native knowledge you have before starting out the better. You need to use Xcode and Android studio for configuring and building your project.
  • Version upgrades it’s not as simple as bumping NPM packages. It may involve updating the native environments as well as the node environment. If you need to bridge custom native modules you would have to learn the native SDK.

Platform inconsistency:

  • Since React Native is calling native platform modules to render UI, the application will look and behave consistent to the platform it runs on. However this also means that sometimes you find identical styling on certain UI elements that is treated differently since the styling attributes have different meanings(I’ve never had an issue that could not be worked around by branching styles depending on targeted platform).

Single threaded:

  • React Native is not entirely single threaded, as developers we lack fine granular control over the threads. This forces developers to learn performant single threaded programming. In order to see more performant applications built in React Native e.g. games we would need to have support for multithreading. Performance is still very good, so far most performance issues I’ve experienced has been from not writing careful JavaScript.

Native SDK:

  • If it’s important that your business has access and control over the latest SDK features. Then React Native would not be the best choice since you will depend on 3rd party libraries to be updated or you would have to maintain custom native modules.

Where to go from here. If you think that you would benefit with React Native in your organisation or for a product then give it a go. If you are partially interested, perhaps other tools using JavaScript to build mobile applications would share some of the traits with React Native and could be a good choice e.g. PWA, Ionic, or Hybird (Native shell rendering web views).

JavaScript is widely used, web technologies are advanced and mobile devices are fast. Don’t build a native app if you don’t really have too.

Learn about how to optimize and profile your React Native application

If you are interested in how to integrate React Native into an existing native application, then check out my friend Adam’s talk: Strangling Legacy With React Native

Hope you enjoyed this article, I would be happy to answer your questions regarding mobile or web development.

Drop a comment below or write me on twitter and follow me on medium to not miss out on future articles 🤗

--

--

Marcus Osterberg

Swedish. I like to code, learn new things and travel new places.