arrow icon
REGISTER

Experiment With the New Architecture of React Native

2023-02-14
Download your copy of the
Ultimate Guide to React Native Optimization

blog content

Need help with Performance Optimization? 
hire us
Need help with Super app development
hire us
Need help with React Native?
hire us
Need help with migration to React Native?
hire us
Our React Native EU Conference is back
register nowlearn more

The following article is part of The Ultimate Guide to React Native Optimization. Including valuable insights from React Native Core Team, it explains the benefits of experimenting with the New Architecture of React Native early on.

Why is this important?

It might be that your app is using an old architecture without the concurrent features of React 18. Or perhaps it’s better to say “current” architecture since it’s still mostly used by production apps. Either way, if you went for New Architecture, you could be leveraging the capabilities of the new rendering system inside your app—and this could greatly benefit your product and improve business results. In this blog post, we’re going to explain what New Architecture is and how it can improve your React Native project.

In other blog posts based on The Ultimate Guide to React Native Optimization, we touch on the following performance-related topics:

Check them out! Now let's jump into the main topic.

Old vs. New Architecture

Both new and old architecture are 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 understand better 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, so it’s important not to 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 issue can be seen when rendering a lot of components in a long list. When the user scrolls fast, there will be a blank space caused by the communication between the JS and native sides being asynchronous. Essentially, 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 new architecture is as good as it may seem. We will also get into the drawbacks that it brings.

What is New 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.

<p-bg-col>Note: Prior to React Native v0.71+ it's possible but way harder to deploy the New Architecture in an app. So that’s the version we are suggesting for you to upgrade.<p-bg-col>

Codegen

A code generation tool that makes JS a source of truth by automating the compatibility between JS and the native side. It allows writing 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 in TypeScript 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

For the time being, React Native is not removing the bridge completely; it’s still there, allowing developers to gradually adopt new architecture and JSI. However, usage of the bridge needs to be explicitly stated (by importing it), so not yet migrated modules won’t work. 

Meta is planning to soon allow apps to run in completely bridge-less mode, which will result in faster app startup due to removing the overhead of loading the bridge every time the app starts.

How to turn on New Architecture

To turn on the New Architecture in your app, you need to update your app to at least React Native 0.68; however, we recommend upgrading to at least React Native 0.71+ because a lot of improvements have been added.

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

  1. Upgrade your app to at least React Native 0.71+, you can use https://react-native-community.github.io/upgrade-helper/ 
  2. Check all third-party libraries that your app depends on; the important thing is that all of them need to be migrated! This might be a long-time blocker for a lot of apps out there. Components that are not yet compatible will show a red box - Unimplemented component: <rte-code><ComponentName><rte-code> - and you will likely notice them. In that case, please let the library maintainers know about it, as this will speed up the adoption.
  3. [Android] Set <rte-code>newArchEnabled=true in gradle.properties.<rte-code>
  4. [iOS] Run <rte-code>RCT_NEW_ARCH_ENABLED=1<rte-code> pod install inside the iOS folder.

Benefits of moving React Native app to New Architecture

Now that you know how New Architecture works, let’s go over its 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 bridgeless mode is 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 than the old one. Apart from removing major bottlenecks, they wanted to create a new solid foundation, allowing 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 the link to the source: https://github.com/reactwg/react-native-new-architecture/discussions/85

Benchmark of rendering 10K views

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

Benchmark of rendering 2K Text components

The old architecture is faster in this scenario because of heavier UI thread consumption.

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

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 nonurgent 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 once 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. 

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 & 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 here) 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 in time. It’s worth calling out that React Native is no different to 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 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 considering starting to plan your migration early on, so you can identify the problems and blockers that your app may be facing. 2023 is the best time to try it, evaluate, ask for support, and give feedback. 

You can get a head start with fine support from the React Native core engineers in solving your app’s build and runtime issues preventing you from migration. Once the new architecture gets stable and turned on by default, the core team will surely focus on the further development of React Native, and hence the migration support time will be reduced.

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.

Author:
Oskar Kwaśniewski
arrow icon
MORE posts from this author

Bundle React Native apps using Webpack features

Discover Re.Pack – a Webpack-based toolkit that allows you to build a React Native app with the full support of the Webpack ecosystem.

learn more

More posts from this category

Ensure your React components perform as intended as your app grows

Discover Reassure - our open-source library that allows you to run performance tests measuring the average rendering time of the in-app components.

business benefits

Performance Optimization

To stay competitive, you need a high-performing app. Improving React Native performance can bring your company many business and tech benefits. To learn more about it, check the page entirely dedicated to React Native Performance Optimization. Discover a real-life example of React Native optimization we performed for Aaqua, a Singaporean platform that enables global users to share their passion through groups.

Bundle React Native apps using Webpack features

Discover Re.Pack – a Webpack-based toolkit that allows you to build a React Native app with the full support of the Webpack ecosystem.

business benefits

Why React Native?

Building an all-in-one platform can bring your company a lot of business and tech benefits like seamless UX experience, global reach, brand growth just to name a few. To learn more about the benefits of using React Native to develop super apps, check out the MoMo case study. Where we helped improve app's performance by migrating architecture to Re.Pack.

stay tuned

Subscribe to our newsletter

You may unsubscribe from these communications at any time. For details see the Privacy Policy.