A deeper look into React Native and its architecture, Part II

6 mins read

In the first part of this article, we saw how the current react native architecture works along with the problems it comes with. The need for a re-implementation was inevitable, and the react native team over at Facebook are close to rolling out the new architecture design, which we will take a brief look at in this blog.

The Re-architecture

React Native New Architecture

In the new implementation we have major changes taking place. As seen from the diagram above, we have new components laid out to form the re-architecture. These are:

  • JavaScript Interface (JSI)
  • Code Gen
  • Fabric
  • Turbo Modules

Let’s take a look at what each of these newly introduced components bring to the table.

  • JavaScript Interface (JSI)

JSI is a lightweight API that makes the JS Side and Native Side of React Native aware of each other. This was, in the old architecture, possible only via communication over the React Native Bridge. Thanks to JSI, there is no need for this bridge anymore.

Translation — JSI replaces React Native Bridge.

This transition brings a whole lot of possibilities to the table, these include:

  • A synchronization of the JS Realm and the Native Realm: Once the completely isolated parts of React Native are now aware of each others existence. This is possible because JSI exposes native methods via C++ Host Objects and lets JS code hold references to these objects. This means that the JS Engine can use JSI to directly invoke methods in the native realm using those references.

This is similar to how in the web we hold references to DOM elements inside JS Code when we write

const container = document.createElement(‘div’)

  • Ability to use any JS Engine: In the old architecture, the React Native Bridge was only compatible with a JS Engine called JSCore. Unlike this behaviour, JSI is completely decoupled from the JS Engine and lets us use other engines like V8, Hermes, etc.

By default, the new architecture will come with Hermes. Its binary size is smaller than other JavaScript engines, such as JavaScriptCore (JSC), it uses less memory at runtime, which is particularly valuable on lower-end Android devices, and more importantly, Hermes will help us compile JavaScript into bytecode ahead of time, thereby improving the app start-up time.

JSI

  • Code Gen

Now you must be asking, how is a loosely typed language such as JavaScript translated to a strictly typed native equivalent?

The answer is: CodeGen. It is a tool that will allow us to automate the compatibility between the JS and Native side. By expecting a typed JavaScript (using Flow or TypeScript), this generator can define the interfaces needed by the new Fabric and Turbo Modules.

  • Fabric Renderer

Fabric is the new UI Renderer that transforms React logic to what the host platform understands, and renders it on the screen. This process is called the render pipeline and has 3 phases:

  1. Render Phase,
  2. Commit Phase, and
  3. Mount Phase

Firstly, the renderer takes the React Element Tree made by React (in JavaScript), and converts it to the C++ equivalent called the React Shadow Tree. This completely removes the dependency on the React Native Bridge.

In the second phase, the renderer commits both the React Element Tree and React Shadow Tree, which promotes them as the next tree to be mounted. It also in parallel schedules the calculation of the layout information (position on screen). This calculation is made by a layout engine called Yoga.

Lastly, the React Shadow Tree, now with the results of the layout calculation, is transformed into a Host Tree View which can be rendered on the screen.

A practical example of how Fabric works can be found in the official documentation.

  • Turbo Modules

Turbo Modules are just newly implemented Native Modules. In the old architecture, all the native modules (such as Bluetooth, GPS, etc) were loaded when the application first starts just in case they are required for use. This caused react native apps to bloat, not to mention the drastic performance effects.

With the new architecture, we have JSI holding references to the native modules, which lets our JS side invoke the methods only when needed. This results in a significantly faster performance, hence the name turbo.

A Recap

The new react native architecture brings reliable solutions to the frequently occurring problems in the current implementation by:

  • Depreciating the bridge and introducing JSI,
  • Being able to use any JSEngine,
  • Communication between the JS and Native side using C++ host object references,
  • Automated compatibility between JS and Native Side,
  • Lazy loading native modules = Turbo Modules,
  • Complete synchronization between threads,
  • Prioritizing time sensitive UI events (like scroll, tap, etc…) by executing them synchronously.

These powerful improvements spark a new era for React Native. Hope we can all indulge in to the updated architecture pretty soon!