Experiment With the New Architecture of React Native

In short

This article, part of The Ultimate Guide to React Native Optimization, delves into the benefits of adopting the New Architecture in React Native. It emphasizes the advantages, such as performance improvements and future readiness, achieved through tools like Fabric, TurboModules, Codegen, and JSI. The guide provides a step-by-step migration process for developers, highlighting the importance of staying updated for maintenance, support, and security reasons.

Originally published in February 2023, updated in April 2024.

Leverage the capabilities of the new rendering system inside your app

Issue: Your app is using old architecture without the concurrent features of React 18

Maybe it's better to say “current” architecture since it's still mostly used by production apps. This term refers to how React Native's two realms (Native and JS) communicate with each other. Both new and old architecture is based on the communication between JavaScript and the native side. Currently, this communication is
handled by the bridge. Let's go over its limitations to easier understand the problems that the New Architecture is trying to solve.

  • It is asynchronous: the JavaScript side submits data to a bridge and waits for the data to be processed by the native side.
  • It's single-threaded (that's why it's important to not overload the JS thread and execute animations on the UI thread). 
  • It adds additional overhead when it comes to the serialization of data from JSON objects.

The bridge is still working fine for most use cases. However, when we start to send a lot of data over the bridge, it may become a bottleneck for our app. This problem can be seen when rendering a lot of components in a long list. In the case when the user scrolls fast, there will be a blank space caused by the communication between the JS and native sides being asynchronous. Essentially what happens is that we are having a “traffic jam” on our bridge with objects waiting to be serialized. The same issue with the bridge being “overloaded” can be seen in native modules sending a lot of data back and forth.

This bottleneck, together with providing a type-safe way of communicating between native and JS, are the main things that the New Architecture is trying to solve. However, not everything about the New Architecture is as good as it may seem. We will also get into the drawbacks that it brings.

Migrate your app to the New Architecture

What is the new React Native architecture?

Starting from React Native 0.68, developers can leverage new capabilities of the framework. The New Architecture relies on a series of tools, which are key components to the new experience. Two most important ones are Fabric and TurboModules. The first one is a new rendering system, and the second one is a new way of writing native modules. We will get into details later in this section.

Codegen and JSI are two new tools improving the developer experience. They are essential to understand how the New Architecture works. Codegen drastically improves DX by generating a lot of native boilerplate code and ensuring type safety. And JSI, a C++ API for interacting with any JS engine.

Note: New Architecture is still considered experimental. Always use the latest version of React Native when using it.

Codegen

A code generation tool that makes JS source of truth by automating the compatibility between JS and the native side. It allows towrite statically typed JS (called JS Spec) which is then used to generate the interface files needed by Fabric native components and TurboModules. Spec consists of a set of types written inTypeScript or Flow that defines all the APIs provided by the native module

Codegen ensures type-safety and compile-time type safety, which means smaller code and faster execution as both realms can trust each other around validating the data every time. To find out more about it, refer to the docs.

JSI

JSI is the foundation of the New Architecture, a C++ API for interacting with any JS engine. In contrast to the bridge which was asynchronous, JSI is synchronous which allows for invoking native functions faster. It lets JavaScript hold references to C++host objects and invoke methods directly on them. This removes the major overhead of asynchronous communication between JS and native by serializing objects using the bridge.

Fabric

Fabric is React Native's new concurrent rendering system, a conceptual evolution of the legacy render system. The core principle is to unify more render logic in C++ to better leverage interoperability between platforms. Host Components like View, Text, etc. are now lazily initialized, resulting in faster startups. Fabric allows us to take advantage of the features introduced in React 18.

TurboModules

This is a new way of writing native modules that also leverages the power of JSI, allowing for synchronous, and an order of magnitude faster data transfer from native to JS and vice versa.

It is a rewrite of the communication layer between JavaScript and platform native modules like Bluetooth, Biometrics, etc. It also allows for writing native code for both platforms using C++ and introduces the lazy loading of modules to speed up your app startup time.

Bridgeless mode

The ultimate goal of the New Architecture is to fully sunset the bridge. Starting from React Native 0.73, you can enable Bridgeless Mode which will disable the creation of the bridge entirely.

This will result in a slightly faster app startup due to removing the overhead of loading the rest of the React Native runtime: error handling, global event emitters, timers, and more.

How to turn on New Architecture

According to the official React Native core team recommendation, in order to turn on the New Architecture in your app, you need to update your app to the latest version of React Native.

To migrate your app to the New Architecture, follow these steps:

  1. Upgrade your app to the latest React Native version, you can use the upgrade helper.
  2. [Android] Set <rte-code>newArchEnabled=true in gradle.properties.<rte-code>
  3. [iOS] Run <rte-code>RCT_NEW_ARCH_ENABLED=1<rte-code> pod install inside the iOS folder.
  4. Run the app in debug and release modes. Look for Components that are not yet compatible – they will show as red boxes – Unimplemented component: <rte-code>ComponentName<rte-code> – and you will likely notice them.
  5. In case of unsupported components, use the Interop Layer through the react-native.config.js file and the <rte-code>unstable_reactLegacyComponentNames<rte-code> option and try again. Take note that the interop layer is not fully compatible with the old rendering and event system, so inconsistencies may be expected in some cases.

Benefits of moving React Native app to New Architecture

Now that you know the basics of how the New Architecture works, let’s go over the benefits.

Performance

Due to the synchronous nature of the new architecture, while communicating with the native side, there will be some performance improvements. The app's startup time will be significantly reduced as every native module will be lazily-loaded. Once the bridgelessmode will be available it will also remove the overhead of loading the bridge at startup. However, not every scenario proves this, in some of the benchmarks architecture performance is worse.

Meta's goal was not to make new architecture X times faster thanthe old one. Apart from removing major bottlenecks they wantedto create a new solid foundation which would allow for new capabilities that could not be developed using previous architecture. Migration of the Facebook app took over a year and they haven't noticed any significant performance improvements or regressions that are perceivable by the end user. However, this doesn't mean that performance improvements won't come in the future. Now that they reworked internals they have a great foundation to build upon.

Let’s go over some performance benchmarks by Alexandre Moureaux from BAM. Here is a link to the source.

Benchmark of rendering 10K views

In this case, the New Architecture proves more efficient than the old one. Using, on average, less CPU but more RAM.

chart showing CPU usage per thread

Benchmark of rendering 2K Text components

In this scenario, the old architecture is faster, mainly because of heavier UI thread consumption.

chart showing rendering 2k text components

The official response from the React Native team is that their internal benchmarks while rolling out the New Architecture to users were neutral across all React Native surfaces in the Facebook app on both Android and iOS. As stated by Samuel Susla in this discussion thread, “In the last years, we conducted dozens of tests in production on millions of devices to assure performance was neutral.”

So in most use cases, you can expect a neutral performance impact without any performance regressions. And keep in mind that the New Architecture is getting better every single day with many developers contributing to the repository, so the results may be totally different by the time you are reading this.

Future readiness

The React Native New Architecture allows your app to leverage Concurrent React features. This improves UI responsiveness, provides Suspense for data fetching to handle complex UI loading schemes, and ensures your app is ready for any further React innovations built on top of its new concurrent engine introduced in React 18.

Let’s see how we can leverage React18’s <rte-code>startTransition<rte-code> API to prioritize between two state updates. In our example, a button click can be considered an urgent update, whereas the <rte-code>NonUrgentUI<rte-code> can be considered a non-urgent update. To tell React about a non-urgent update, we can wrap the <rte-code>setState<rte-code> in the <rte-code>startTransition<rte-code> API. This allows React to prepare a new UI and show the old UI until a new one is prepared. 

In our example, we wrapped <rte-code>setNonUrgentValue<rte-code> in <rte-code>start-Transition<rte-code> and told React that <rte-code>nonUrgentValue<rte-code> is a transition and not so urgent, it may take some time. We’ve also added a conditional <rte-code>backgroundColor<rte-code>. When you run this example, you will see that once you click on the button, the view will retain its old UI, e.g., if we start at value 1, the UI will be green.

Once you click on the button, the Value text UI will be updated, but the UI for the container will remain green until the transition is completed, and the color will change to red due to the new UI being rendered. That’s the magic of React’s concurrent rendering.

To understand it better, assume that wrapping an update in <rte-code>startTransition<rte-code> renders it in a different universe. We don’t see that universe directly, but we can get a signal from it using the <rte-code>isPending<rte-code> variable returned from the <rte-code>useTransition<rte-code> hook. Once the new UI is ready, both universes merge together to show the final UI.

To understand it better, let’s visualize the code snippet we just went through. The image below shows a comparison of when we use <rte-code>startTransition<rte-code> and when we don’t. Looking at the image, we see that React flushes the urgent update right off, which happens due to calling <rte-code>setValue<rte-code> without wrapping it in <rte-code>startTransition<rte-code>.

Next, we see that React shows the old UI (viewed in green) for the UI that depends on the non-urgent updates, which means the updates that are wrapped in <rte-code>startTransition<rte-code>. We also see a Pending text displayed; this is a way for React18 to tell us that the new UI depending on this state is not yet ready. Once it’s ready, React flushes it and we don’t see the Pending text anymore, and the view color changes to red.

On the other hand, if we don’t use <rte-code>startTransition<rte-code>, React tries to handle both updates as urgent and flushes when both are ready. This certainly has a few downsides, such as the app trying to render some heavy UI all at once, which may cause jarring effects for the users. With React18, we can handle this by delaying the updates that are not urgent. 

react 18 start transition

There are some other noticeable features in React18 that you might want to check out by playing with the linked sandboxes from React’s official website. See useDeferredValue and startTransition with Suspense.

Maintenance and support

The React Native core team is committed to offer support for the 3 latest versions of React Native (you can check the support policy) and the React core team plans new features built on the concurrent rendering engine. It’s important to not stay behind as the cost of paying the tech debt will get higher with time. It’s worth pointing out that React Native is no different from any other software project in this regard. Not updating dependencies may not only cause your team to spend more time on this task when it’s unavoidable. It can also expose your app to security vulnerabilities already patched in the upstream.

The React Native team has the dedicated capacity to help the community solve their app and library problems regarding new architecture adoption in close cooperation. Although it's not stable yet, it's worth trying out in your app today. Especially considering that since React Native v0.72 the Interop Layer exists which allows running most of the old architecture components with apps that enabled the New Architecture.

Need help with performance? Give us a shout!

If you’re struggling with improving your app performance, get in touch with us. Our React Native development company is an official Meta partner and community leader. We’ve delivered high-quality solutions for dozens of international clients, from startups to enterprises, and created some cool Open Source projects like Re.Pack or Reassure. Now’s the time we help your business grow.

FAQ

No items found.
React Galaxy City
Get our newsletter

By subscribing to the newsletter, you give us consent to use your email address to deliver curated content. We will process your email address until you unsubscribe or otherwise object to the processing of your personal data for marketing purposes. You can unsubscribe or exercise other privacy rights at any time. For details, visit our Privacy Policy.

Callstack astronaut
Download our ebook

I agree to receive electronic communications By checking any of the boxes, you give us consent to use your email address for our direct marketing purposes, including the latest tech & biz updates. We will process your email address and names (if you have entered them into the above form) until you withdraw your consent to the processing of your names, or unsubscribe, or otherwise object to the processing of your personal data for marketing purposes. You can unsubscribe or exercise other privacy rights at any time. For details, visit our Privacy Policy.

By pressing the “Download” button, you give us consent to use your email address to send you a copy of the Ultimate Guide to React Native Optimization.