React Native serves as a practical technological solution, allowing the development of iOS and Android applications with native rendering capabilities using React and JavaScript. We built the Hyperswitch SDK using React Native to ensure code reusability and cross platform compatibility. Let's revisit the basics and look at everything React Native has to offer!

Why React Native?

There are two primary benefits of using React Native. Firstly, it enables web developers to write mobile applications that feel native using the most popular JavaScript UI library

Secondly, a significant portion of code written in React Native can be shared between platforms, streamlining concurrent development for both iOS and Android. Thus reducing engineering overhead involved in making separate iOS and Android Applications.

So, spill the beans on how this thing actually works, real quick!

Lets have a 10,000 ft view of how this thing works on different Operating systems.

React Native  brings JavaScript code and Native code (Java/Kotlin for Android and Objective-C/Swift for iOS)  together and make them work seamlessly like a seasoned orchestrator.

The native code executed directly on the device but JavaScript needs a virtual machine to be run on.

So, you must be aware how JS works on a browser, it needs a JavaScript Runtime Environment which in turn contains a JavaScript Engine.

And the JS engine is responsible for interpreting and executing JavaScript code in a runtime environment. Some major JS engines are V8 (used in Chrome), SpiderMonkey (used in Firefox), and JavaScriptCore (used in Safari).


Ok that makes sense, but how do mobile devices gets groovy with JS?

  

The iOS and devices have a built-in JavaScript engine called JavaScriptCore written in C++, which will compile and execute our JS code. 

Since Android devices lack a native JS engine, React Native addresses this by including the JavaScriptCore engine as part of its framework.

However in the latest versions of react native, Hermes is the default JS engine. Hermes brings to the table enhancements in startup time, reduced memory usage, and a smaller app size as compared to JavaScriptCore

So the JavaScript code runs essentially on JS engine only and by knowing this we have achieved another level of abstraction about how React Native works under the hood.


How JS and native code written in Java/Obj C talk to each other?


The native code for Android (Java/Kotlin) and iOS (Objective-C/Swift) are composed in different programming languages. 

They lack a direct means to communicate to JS code. However, there's a clever workaround: they establish communication indirectly by utilizing a shared data format—JSON. This communication is facilitated by a group of programs known as the Bridge. It enables the exchange of information between the JavaScript and Native layers via JSON messages.

The idea is the same as in the case of web applications, where the frontend and backend layers do not need to know anything about each other  but they still understand the information they exchange.

A Glimpse of React Native's Build and Runtime

When we're putting together everything to make our app, the native code written in Java or Objective-C becomes binary files in Java and C++. 

The code written in JavaScript gets bundled up using something called the Metro bundler. Metro does a job similar to the Webpack bundler for web application, but it's specially fine tuned for React Native.

During the runtime, the JS code will run on the JavaScript VM, and native code runs directly on the device. The Bridge will transfer serialized messages between the two eco-systems. The messages are then deserialized and dealt with.​

Threads In React Native

What are Threads?

A thread represents a sequence of instructions executed by the CPU. In simpler terms, it is a pathway of execution.

Essentially, there are three threads of primary importance in React Native carry that takes care of all necessary operations.

Main Thread/Native UI Thread 

 This is the primary native thread where the app runs. It handles user interactions, showing things on the device screen, and it's the same thread used in all fully native applications.

Shadow Thread 

This thread kicks off with the JavaScript thread. Its job is to figure out where things should go on the screen and build a structure of layout instructions in the JavaScript thread. React Native uses a layout engine called Yoga, which turns flexbox-based layouts into something the device can understand. It also comes into play when an app needs info from the device, like if you're working on animations and need the Native driver to handle them.

JavaScript Thread 

This is where the app's main operations happen, such as running JavaScript and React code for the business logic.

Demystifying relationship between threads and bridge

When the JavaScript thread requires access to specific native modules, for instance Bluetooth, it must transmit a message to the native thread. The JavaScript thread will dispatch a serialized JSON message to the bridge, which will optimize and relay it to the native thread. Subsequently, the message will be decoded on the native thread, leading to the eventual execution of the necessary native code.

 Unmasking the Hitches: The Not-So-Cool Side of React Native Bridge


The bridge has some inherent issues and limitations.

1. Asynchronous: It worked like passing notes between two layers, and one had to wait for the other, even when it wasn't necessary.
Although asynchronous information exchange through the bridge is generally extremely fast, there are situations where it may prove insufficient, and opting for a synchronous approach would be more advantageous. Issues may arise in certain edge cases when relying solely on asynchronous communication.

2. Single-threaded: Think of it like doing one thing at a time on a single road. Everything in the JavaScript world had to happen on this one road.

3. Extra Work: When one layer needed to talk to the other, it had to package the information in a certain way (serialize), and the other layer had to unpack it (deserialize). This was like putting things in a box before sending them, and then opening the box to use them. Even though they chose a simple and easy-to-read format (JSON), it added a bit of work.

React Native New Architecture

The New Architecture made things better by saying goodbye to the old Bridge and welcoming a new way for different parts of the app to talk to each other. They introduced something called the JavaScript Interface (JSI), which  that lets JavaScript and C++ understand each other. It facilitates allows a JavaScript object to hold a reference to a C++ and vice-versa.

Now, if one type of code wants to ask the other to do something, it can just directly talk to it without waiting or doing extra work. This has a bunch of cool advantages:

1. No More Waiting: Some things that used to take time and wait around can now happen right away. Now it is possible to synchronously execute functions that should not have been asynchronous in the first place.

2. Less Extra Work: Before, they had to package and unpack the information each time they talked. Now, they can just share info without going through all that trouble i.e the New Architecture doesn't have to serialize/deserialize the data anymore

3. Sharing is Caring: With this new way, they can easily use the same code on different devices without too much hassle. It's like having a set of tools that works well everywhere. By introducing C++,  now it is  possible to abstract all the platform agnostic code, making it easier to share seamlessly across different platform.

4.  Enforcing Type Safety: In order to make it possible for JS to properly invoke methods on C++ objects and vice-versa, a layer of code automatically generated has been added. The code is derived from a JavaScript specification that requires typing using either Flow or TypeScript.​​