Personal introduction

Those who are familiar with me should know that ALTHOUGH I have been mainly involved in Flutter, the GSY App series projects were actually React Native at the beginning, followed by Weex and Flutter. Therefore, I have always had the “first love” for RN. It basically took me into the front-end and cross-platform space, and I just happened to read about it recently, just to see what’s coming in the years to come.

As of now, React Native’s version number is 0.67; I looked at GSYGithubApp that hasn’t been updated for two years. The React Native version is 0.61. It has been upgraded from 61 to 67 in two years.

The body of the

Content Reference:Medium.com/coox-tech/d…

With the release of the RN team’s article on in-depth understanding of React Native’s new architecture, the main changes brought by this new architecture are as follows:

    1. JavaScript Interface(JSI)
    1. Fabric
    1. Turbo Modules
    1. CodeGen

In an RN App, all JS code is packaged into a JS Bundle and stored locally. When an RN App is running, there are generally three threads:

  • JavaScript thread: belongs to the JS engine and is used to run the JS Bundle.
  • 2. Native/UI thread: run Native Modules and process UI rendering, user gestures and other operations;
  • Shadow thread: Calculates the layout of elements before rendering.

In RN, JS threads and Native threads interact via a bridge, and the data exchanged must be converted to JSON. This bridge can only handle asynchronous communication.

JavaScriptCore: JavaScript engine, React Native uses it to execute JavaScript code.

Yoga: Layout engine, calculate UI position;

JavaScript Interface (JSI)

Currently RN uses Bridge Module to communicate with JS and Native threads. Every time the Bridge is used to send data, it needs to convert it to JSON and decode the data when it receives it.

This means that JavaScript and Native are directly isolated, meaning that the JS thread cannot directly call methods on the Native thread.

The other is; Messages sent over the Bridge are asynchronous in nature, and requiring simultaneous execution of JS code and Naitve was previously impossible.

For example, if the JS thread needs to access native modules (such as Bluetooth), it needs to send a message to the native thread. The JS thread will send a JSON message via the Bridge, and then the message will be decoded on the Native thread. Eventually, the required native code will be executed.

In the new architecture, Bridge will be replaced by a module called JavaScript Interface, a lightweight generic layer written in C++ that the JavaScript Engine can use to execute directly or call native.

The generic layer means: JSI makes JavaScript interfaces separate from Engine, which means the new architecture allows RN to use other JavaScript engines directly, such as Chakra, V8, Hermes, and so on.

How does JSI get JavaScript to call native methods directly?

In JSI, Native methods are exposed to JS through C++ Host Objects, and JS can hold references to these Objects and use these references to call the corresponding methods directly.

This is similar to how javascript code on the Web can save a reference to any DOM element and call a method on it:

const container = documentThe createElement method (" div ");Copy the code

For example, the container here contains references to DOM elements initialized in C++, so if we call any method on the container, it will call the method on the DOM element.

JSI works in a similar way. JSI will allow JS code to save references to Native Modules, and JS can call Native methods directly from references.

To sum it up:

  • JSI will support other JS engines;
  • JSI allows synchronization between threads to execute with each other without requiring performance costly operations such as JSON serial numbers;
  • JSI is written in C++ and can be easily ported to other systems such as TVS and watches.

Second, the Fabric

Fabric is the new rendering system that replaces the current UI Manager.

Prior to Fabric, when the App runs, React executes your code and creates a ReactElementTree in JS, based on which the renderer creates a ReactShadowTree in C++.

The UI Manager uses the Shadow Tree to calculate the location of UI Elements. Once the Layout is complete, the Shadow Tree is converted to a HostViewTree consisting of Native Elements (e.g. RN will become a ViewGroup in Android and A UIView in iOS.

Previously, communication between threads took place on the Bridge, which meant time spent on transfers and data replication.

For example, if a ReactElementTree node happens to be a , then the ReactShadowTree node will also be an Image, but the data must be copied and stored separately in both nodes.

In addition, because the JS and UI threads are out of sync, the App may get stuck in some cases due to frame loss (e.g., scrolling through a FlatList with a lot of data).

Thanks to the previous JSI, JS can directly call Native methods, which in fact include UI methods, so JS and UI threads can be executed synchronously to improve the performance of list, jump, gesture processing, etc.

With the new Fabric rendering, user interactions (such as scrolling, gestures, etc.) can be performed synchronously in the main thread or Native thread first, while other tasks such as API requests are performed asynchronously.

In addition, the new Shadow Tree will be immutable and will be shared between JS and UI threads for direct interaction.

Previously RN had to maintain two hierarchies of DOM nodes, but since Shadow trees can now be shared, the parts that reduce memory consumption will also be optimized accordingly.

Third, Turbo Modules

All Native Modules used by JS in previous architectures (such as Bluetooth, geolocation, file storage, etc.) had to be initialized before the application opened, which meant that even though the user didn’t need some module, it still had to be initialized at startup.

Turbo Modules are basically enhancements to these older Native Modules. As mentioned earlier, JS will now be able to hold references to these Modules, so JS code can load the corresponding Modules only when needed, which can significantly reduce the startup time of RN applications.

Fourth, the Codegen

Codegen is primarily a static type checker used to ensure normal communication between JS code and C++ JSI. Using typed JS as a reference source, Codegen defines interfaces that can be used by Turbo modules and fabrics. Additionally, Codegen generates Native code at build time, reducing runtime overhead.

From the above four points, RN will see a performance and experience leap forward in 2022. The new architecture will solve the fundamental design problems that RN has been criticized for many years.

Skia

In addition, react-native-SKia is still in its alpha release stage, but it also brings new possibilities to RN.

It is well known that The cross-platform performance and decoupling of Flutter comes from direct use of Skia rendering rather than system controls, and RN now has similar support for Flutter.

React-native-skia requires the support of react-native@>=0.66. Currently, its operations are still very primitive canvas behavior, such as drawing circles by Circle and configuring overlapping modes by blendMode.

import {Canvas, Circle, Group} from "@shopify/react-native-skia";
 
export const HelloWorld = () = > {
  const width = 256;
  const height = 256;
  const r = 215;
  return (
    <Canvas style={{ flex: 1}} >
      <Group blendMode="multiply">
        <Circle cx={r} cy={r} r={r} color="cyan" />
        <Circle cx={width - r} cy={r} r={r} color="magenta" />
        <Circle
          cx={width/2}
          cy={height - r}
          r={r}
          color="yellow"
        />
      </Group>
    </Canvas>
  );
};
Copy the code

It also allows you to use SkiaView directly and use canvas to draw the graphics you need:

import {Skia, BlendMode, SkiaView, useDrawCallback} from "@shopify/react-native-skia";
 
const paint = Skia.Paint();
paint.setAntiAlias(true);
paint.setBlendMode(BlendMode.Multiply);
 
export const HelloWorld = () = > {
  const width = 256;
  const height = 256;
  const r = 215;
  const onDraw = useDrawCallback((canvas) = > {
    // Cyan Circle
    const cyan = paint.copy();
    cyan.setColor(Skia.Color("cyan"));
    canvas.drawCircle(r, r, r, cyan);
    // Magenta Circle
    const magenta = paint.copy();
    magenta.setColor(Skia.Color("magenta"));
    canvas.drawCircle(width - r, r, r, magenta);
    // Yellow Circle
    const yellow = paint.copy();
    yellow.setColor(Skia.Color("yellow"));
    canvas.drawCircle(width/2, height - r, r, yellow);
  });
  return (
    <SkiaView style={{ flex: 1 }} onDraw={onDraw} />
  );
};
Copy the code

Currently, the library supports actions like Image, Text, Shader, Effects, Shapes, and Animations. The implementation of Flutter is very similar to that of Flutter, for example:

SkiaDrawView on Android is actually TextureView, and the drawing logic is written by the author on Reactskia. Here we just use the support of TextureView surface and TouchEvent.

IO /react-nativ shopify.github. IO /react-nativ…

It can be predicted that there are still many problems to be solved with the Current React-native SKia, but it is a good attempt for RN to use rich Canvas capability more efficiently.