React Native’s Improved 2023 New Architecture

2022 Brought React Native to a New Level

React Native is an open-source framework developed by Facebook for building mobile applications using JavaScript and React.

With React Native, developers can create native apps for iOS, Android, and other platforms using a single codebase. This means that there’s no need of having to write separately.

React Native offers a number of advantages over traditional frameworks, like allowing developers to build apps using JavaScript and CSS.

This makes starting with mobile app development a piece of cake!

React Native has a highly modular and flexible architecture, this enables you to reuse components across different projects. It reduces workflow and improves code quality [check debugging], and you can focus on creating new features.

So…Get creative and delve into: Splash Screens in React Native, animations, vision camera, video, image picker, vector icons and maps!

Architecture... Let's Fill the Gap

Architecture – Old and New

The Old Architecture used to work by using The Bridge. The consumer can read the data, deserialize it and execute the required operations. However, there are some limitations to it:

  • It’s asynchronous
  • It’s single-threaded: JS used to work on a single thread.
  • It imposes extra overheads: JSON is chosen for its simplicity and human-readability, but despite being lightweight, it’s a cost to pay.

The New Architecture advocates the JavaScript Interface (JSI). The JSI allows a JavaScript object to hold a reference to a C++ [back and forth].

This enables invoking methods directly on it. Like a C++ object can now ask a JavaScript one to execute a method in the JavaScript [back and forth].

This unlocked several benefits:

  • Synchronous execution
  • Concurrency: it’s possible from JavaScript to invoke functions that are executed on different threads.
  • Lower overhead: there are no serialization taxes to pay.
  • Code sharing: by introducing C++ you can now share it easily between platforms.
  • Type safety: the code is generated starting from some JS specification that must be typed through Flow or TypeScript. [You’ll find some then]

These are the foundations for upcoming enhancements. For example, it has been possible to develop a new renderer which will be explored next.

So, What's New in React Native?

There’re some major changes that are already settled in since mid-2022.

First and foremost, if you want to start migrating into React Natives new architecture, just click here The Migration Guide and follow its steps.

Hands on for creating a custom Fabric component or a TurboModule with a step-by-step approach. It guides you so as to adapt your existing app or library to use the New React Native Architecture.

Find painstaking articles of the React Native internals. The Fabric section helps you grasp the rendering pipeline in the New Architecture world.

React Native 0.68 is what has been chosen as support for the Fabric Renderer and the TurboModule system. If you want to be up-to-date with the latest.

You can fin in React Native’s blog posts “the Architecture section to the website, where you can find several in-depth guides about internals of the new systems.”

Let’s Get The Ball Rolling!

We’ll cover the following new features of the React Native’s New Architecture:

  1. Fabric Renderer
  2. Turbo Modules
  3. CodeGen

More the visual type? Click and watch!

There’s a caveat. All of these are iterating as we speak, so CTA▶️ Use it and give feedback! 🔛

The Fabric Renderer and TurboModule system are two separate technologies developed by Facebook to improve the performance and UX of their mobile applications.

CodeGen is not a mandatory tool. Nevertheless, if you believe that time is of the essence, it’s a must for you.

The Fabric Renderer – Get Hands on!

The Fabric Renderer is a cross-platform UI rendering engine that allows for faster rendering and smoother animations on mobile devices. It uses a declarative approach to building user interfaces.

Fabric Native Components instead of Legacy Native Components allows us to embrace React Natives New Architecture benefits [taken from React Native’s blog post]:

  • Strongly typed interfaces that are consistent across platforms.
  • The ability to write your code in C++ reducing the need to duplicate implementations across platforms.
  • The use of JavaScript interface [JSI] for native code allows for more efficient communication between native and JavaScript code than the bridge.
  • A Fabric Native Component is created starting from a JavaScript specification. Then CodeGen creates some C++ scaffolding code to connect the component-specific logic. Once the component is properly connected with the scaffolding code, it is ready to be imported and used by an app.

Follow the next steps for creating a Fabric Native Component:

  1. Define a set of JavaScript.
  2. Configure the component so that CodeGen can create the shared code and it can be added as a dependency for an app.
  3. Write the required native code.

Once done, the component is ready for the app.

1. Folder Setup

In order to keep the component decoupled from the app, it’s a good idea to define the module separately and then add it as a dependency to your app later. This also allows its release as open-source.

For this guide, you are going to create a Fabric Native Component that centers some text on the screen.

  1. Create a new folder at the same level of the app and call it RTNCenteredText.
  2. In this folder, create three subfolders: jsios, and android.

You should see this:

├── MyApp
└── RTNCenteredText
├── android
├── ios
└── js

2. JavaScript Specification

The New React Native Architecture requires interfaces specified in a typed dialect of JavaScript  (either Flow or TypeScript). 

Codegen works to generate code in C++, Objective-C++, and JS. There are two musts for the file:

  1. The file must be named <MODULE_NAME>NativeComponent, with a .js or .jsx extension when using Flow, or a .ts, or .tsx extension when using TypeScript. Codegen only looks for files matching this pattern.
  2. The file must export a HostComponent object.

Find specifications of the RTNCenteredText component in both Flow and TypeScript. Create a RTNCenteredTextNativeComponent file with the proper extension in the js folder.

import type {ViewProps} from 'ViewPropTypes';
import type {HostComponent} from 'react-native';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';

export interface NativeProps extends ViewProps {
      text?: string;
      // add other props here
}

export default codegenNativeComponent<NativeProps>(
      'RTNCenteredText',
        ) as HostComponent<NativeProps>;

Flow:

// @flow strict-local

import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from 'react-native';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';

type NativeProps = $ReadOnly<{|
      ...ViewProps,
      text: ?string,
      // add other props here
|}>;

      export default (codegenNativeComponent<NativeProps>(
            'RTNCenteredText',
): HostComponent<NativeProps>);

You need imports that are required by every Fabric Native Component:

  • The HostComponent: type the exported component needs to conform to.
  • The codegenNativeComponent function: responsible to actually register the component in the JavaScript runtime.

The second section of the files contains the Props of the component information that let you customize React Native components. In this case, you want to control the text property of the component.

Finally, codegenNativeComponent generic function, called passing the name of the component.

3. Component Configuration

Next, you need to add some configuration for CodeGen and auto-linking shared between iOS and Android.

The shared configuration is a package.json file that will be used by yarn when installing your module. Create the package.json file in the root of the RTNCenteredText directory.

{
"name": "rtn-centered-text",
"version": "0.0.1",
"description": "Showcase a Fabric Native Component with a centered text",
"react-native": "js/index",
"source": "js/index",
"files": [
         "js",
         "android",
         "ios",
         "rtn-centered-text.podspec",
         "!android/build",
         "!ios/build",
         "!**/__tests__",
         "!**/__fixtures__",
         "!**/__mocks__"
],
          "keywords": ["react-native", "ios", "android"],
              "repository": "https://github.com/<your_github_handle>/rtn-centered-text",
              "author": "<Your Name> <your_email@your_provider.com> (https://github.com/<your_github_handle>)",
              "license": "MIT",
              "bugs": {
               "url": "https://github.com/<your_github_handle>/rtn-centered-text/issues"
},
                "homepage": "https://github.com/<your_github_handle>/rtn-centered-text#readme",
                "devDependencies": {},
                "peerDependencies": {
                        "react": "*",
                        "react-native": "*"
},
                        "codegenConfig": {
                            "name": "RTNCenteredTextSpecs",
                            "type": "components",
                            "jsSrcsDir": "js"
}
}

The upper part contains descriptive information. Make sure to make any needed update embedded in <>: replace all the occurrences of the <your_github_handle>, <Your Name>, and <your_email@your_provider.com> tokens.

Then there are the dependencies for this package. You’ll need react and react-native.

Finally, the CodeGen configuration is specified by the codegenConfig field. It contains an array of libraries, each of which is defined by three other fields:

  • name: The name of the library. By convention, you should add the Spec suffix.
  • type: The type of module contained by this package. In this case, it is a Fabric Native Component, thus the value to use is components.
  • jsSrcsDir: the relative path to access the js specification that is parsed by Codegen.

iOS: Create the .podspec file

For iOS, you’ll need to create a rtn-centered-text.podspec file to define the module as a dependency for your app. It will stay in the root of RTNCenteredText, with the ios folder.

The file will look like this:

require "json"

package = JSON.parse(File.read(File.join(__dir__, "package.json")))

Pod::Spec.new do |s|
s.name = "rtn-centered-text"
s.version = package["version"]
s.summary = package["description"]
s.description = package["description"]
s.homepage = package["homepage"]
s.license = package["license"]
s.platforms = { :ios => "11.0" }
s.author = package["author"]
s.source = { :git => package["repository"], :tag => "#{s.version}" }

s.source_files = "ios/**/*.{h,m,mm,swift}"

install_modules_dependencies(s)
end

The .podspec file has to be a sibling of the package.json file, and its name is the one we set in the package.json‘s name property: rtn-centered-text.

The first part of the file prepares some variables that we use throughout the file. Then, there is a section that contains some information used to configure the pod, like its name, version, and description.

All the requirements for the New Architecture have been encapsulated in the install_modules_dependencies. It also automatically installs the React-Core dependency in the old architecture.

Android: build.gradle and the ReactPackage class

To prepare Android to run CodeGen you have to:

  1. Update the build.gradle file.
  2. Create a Java/Kotlin class that implements the ReactPackage interface.

At the end of these steps, the android folder should look like this:

android
├── build.gradle
└── src
└── main
└── java
└── com
└── rtncenteredtext
└── CenteredTextPackage.java

The build.gradle file. Create a build.gradle file in the android folder, with the following contents:

buildscript {
     ext.safeExtGet = {prop, fallback ->
     rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
     repositories {
        google()
        gradlePluginPortal()
}
        dependencies {
            classpath("com.android.tools.build:gradle:7.3.1")
}
}

apply plugin: 'com.android.library'
apply plugin: 'com.facebook.react'

            android {
                 compileSdkVersion safeExtGet('compileSdkVersion', 33)
                 namespace "com.rtncenteredtext"

                 defaultConfig {
                    minSdkVersion safeExtGet('minSdkVersion', 21)
                    targetSdkVersion safeExtGet('targetSdkVersion', 33)
                    buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", "true")
}
}

                    repositories {
                       mavenCentral()
                       google()
}

                       dependencies {
                           implementation 'com.facebook.react:react-native'
}

The ReactPackage class

Then, you need a class that implements the ReactPackage interface. To run the CodeGen process, you don’t have to completely implement the React Native Package class.

Create an android/src/main/java/com/rtncenteredtext folder and, inside that folder, create a CenteredTextPackage.java file.

package com.rtncenteredtext;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.Collections;
import java.util.List;

public class CenteredTextPackage implements ReactPackage {

       @Override
       public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
          return Collections.emptyList();
}

          @Override
          public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
              return Collections.emptyList();
}

}

The ReactPackage interface is used by React Native to understand what native classes the app has to use for the ViewManager and Native Modules exported by the library.

4. Native Code – Last Step

It requires you to write some native code to connect the JavaScript side of the Component to what is offered by the platforms. Requiring two steps:

  1. Run CodeGen to see what would be generated.
  2. Write the native code that will make it work.

When developing a React Native app that uses a Fabric Native Component, the app is accountable for generating the code using CodeGen. However, when developing a Fabric Component as a library, it needs to reference the generated code.

Find more information on Codegen here. And if you want to dig into iOS follow this link!

TurboModule

The TurboModule system is a technology that optimizes the performance of native modules in React Native applications.

Native modules are pieces of code written in platform-specific languages such as Java or Objective-C that can be called from JavaScript code in a React Native application.

It reduces their startup time and memory usage, making React Native apps faster and more responsive. Please, get hands-on and codes to run HERE!

Two technologies that help to make Facebook’s mobile apps more efficient for users and devs.

Click if you want to keep on exploring!

Rounding up!

There’s a lot to discover and keep on improving, that’s why we are adamant on receiving your feedback and iterate! React Native is a powerful and versatile framework that is well-suited for building a wide range of mobile applications.

Whether you’re a seasoned developer or just starting out, React Native is definitely worth considering for your next mobile app project. Check our posts and Instagram to find out more!