3

foreword

This article mainly introduces the introduction of react-native (hereinafter referred to as RN), and the similarities and differences between it and the front end

The article does not involve the specific implementation of the function

Choose the advantage

Let's talk about why many people choose to use RN, the difference between its corresponding features and ordinary Web

  1. Front-end resources, ecological exchange

Because the languages used are JS and react, it can be switched seamlessly for the front end, and he can also use various front-end packages

On the JS side, Android and iOS are the same set of code

  1. Hot update

Many reasons for choosing to use RN is that there are hot updates

Briefly explain the hot update. When running the APP, we can replace the js layer in real time through the received notification. After the replacement is completed, the APP generally needs to be restarted. At this time, the user can be asked, or it can be reloaded at the next restart. Enter new JS code

This can ensure that the js environment used by the user can be newer. If it is an update of the native APP, the user needs to go to the app store to download it again.

  1. native support

RN interacts with native through bridging, and integrates into native APP at page level

Many of his components, methods call native methods/components, which have better performance than webview

Horizontal comparison of cross-end frames

A simple comparison of RN and Flutter

surroundings

无论是RN Flutter ,都需要Android 和IOS 的开发环境,也就是JDKAndroid SDKXcode , The difference is that:

  • RN requires npm, node, react-native-cli and other configurations.
  • Flutter flutter sdk 8ef6473a34894a391a14200ea12735d7---和Android Studio / VSCode上的DartFlutter

For the front end, the RN environment is relatively friendly

Implementation principle

On Android and IOS , Flutter and React Native both require a native platform by default
Activity / ViewController support, and it belongs to a "single page application" at the native level, ** and the biggest difference between them is actually the UI construction:

  • RN:

React Native is a set of UI frameworks. By default, React Native will load JS files under Activity , then run it in JavaScriptCore to parse the Bundle file layout, and finally stack a series of native The control is rendered.

To put it simply, the page layout is configured by writing JS code, and then React Native will finally parse and render it into a native control , such as <View> label corresponding to ViewGroup/UIView , <ScrollView> corresponding to the label ScrollView/UIScrollView , <Image> label corresponding to ImageView/UIImageView and so on.

  • Flutter:

The vast majority of Flutter Widget are platform-independent, the developer develops the app based on Framework , while Framework runs on Engine , by Engine for adaptation and cross-platform support. This cross-platform support process is actually to "dataize" the Widget in the Flutter UI, and then draw it directly to the screen through the Engine on the Skia .

Similar to front-end canvas drawing

This section is from the article: https://www.jianshu.com/p/da80214720eb

shortcoming

  • RN:

    • It is not fully compatible with W3C specifications. For example, in W3C, you can easily set the size and thickness of the rounded corners, and the border is implemented and dashed, but on the client side, this is more difficult to implement. Therefore, these technologies can only support the W3C standards to a limited extent.
    • js running performance bottleneck.
    • The performance bottleneck of data communication.
  • Flutter:

    • Unable to dynamically update.
    • Memory and package size usage.
    • The cost of learning is high and the ecology is insufficient.

js runtime environment

When using RN, JS code will run on two different environments:

  • In most cases, RN uses JavaScriptCore , the JavaScript engine used by Safari. But on iOS JavaScriptCore doesn't use just-in-time compilation technology (JIT), because in iOS apps don't have permission to write and execute memory pages (and therefore cannot generate code dynamically).
  • When debugging with Chrome, all JavaScript code runs in Chrome and communicates with native code via WebSocket. The operating environment at this time is the V8 engine .

So when we start debugging, there will be some differences from the official running environment

RN has built in Babel converter. Therefore, we do not need to configure many grammars babel . The grammar environment can be used directly and you can see the specific configuration here .

timer

There are timers for animations in RN: InteractionManager

A big reason why native apps feel smooth is to avoid heavy lifting during interactions and animations.
In RN, it is limited because we only have one thread of JavaScript execution. So there InteractionManager to make sure all interactions and animations are handled before doing the heavy lifting.

 InteractionManager.runAfterInteractions(() => {
  // ...需要长时间同步执行的任务...
});

Compared to several other timers:

  • requestAnimationFrame() : code used to execute the animation to control the view over a period of time
  • setImmediate/setTimeout/setInterval() : Execute code later. Note that this may delay the animation currently in progress.
  • runAfterInteractions() : Execute the code later, without delaying the currently running animation.

Hermes engine

Hermes is a new open source JavaScript engine optimized for RN applications. For many applications, enabling the Hermes engine can optimize startup time, reduce memory usage and space usage.

Features of Hermes

  • Precompiled bytecode (the engine loads binary code more efficiently than running JS scripts)
  • No JIT compiler (reduced engine size, optimized memory footprint, but the performance of running JS scripts directly is worse than V8 and JSC)
  • Garbage collection strategy for mobile

Optimization principle

The traditional JavaScript engine usually completes the code execution in the mode of the above figure. In the compilation stage, only babel escape and minify compression are completed. The product is still a JavaScript script. The tasks of interpretation and execution need to be completed at runtime (such as the V8 engine, which will also be executed at runtime). The obvious disadvantage is that it needs to be interpreted and executed at runtime, and even requires system resources to perform compilation tasks.

The Hermes engine uses the aot compilation method to prepend the interpretation and compilation process to the compilation stage, and only complete the execution of the machine code at runtime, which greatly improves the operating efficiency.

native ui components

One advantage of RN is that it can insert native components to improve the performance of APP. If we want to use ---1399288d6b09d19651108ad59c875a7a js in ImageView , then we need these steps:

  1. Create a subclass of ViewManager .
  2. Implement the createViewInstance method.
  3. Property setters for exported views: use the @ReactProp (or @ReactPropGroup ) annotation.
  4. Register this view management class in the application package createViewManagers .
  5. Implement JavaScript modules.

The above is the addition of Android, relatively speaking, iOS will be simpler:

  • First create a subclass of RCTViewManager .
  • Added RCT_EXPORT_MODULE() macro tag.
  • Implement the -(UIView *)view method.
 // RNTMapManager.m
#import <MapKit/MapKit.h>

#import <React/RCTViewManager.h>

@interface RNTMapManager : RCTViewManager
@end

@implementation RNTMapManager

RCT_EXPORT_MODULE(RNTMap)

- (UIView *)view
{
  return [[MKMapView alloc] init];
}

@end

In JS use:

 // MapView.js

import { requireNativeComponent } from 'react-native';

// requireNativeComponent 自动把'RNTMap'解析为'RNTMapManager'
export default requireNativeComponent('RNTMap');

// MyApp.js

import MapView from './MapView.js';

...

render() {
  return <MapView style={{ flex: 1 }} />;
}

This is a simple display, about passing a value is to judge more attributes

In addition to native components, js can also pass values to the mobile terminal, add listening events (including promise callbacks), and the corresponding mobile terminals can also

This forms a complete communication system at both ends

Link native library

The above picture is react-native-splash-screen library install and link

When we use the three-party native library, we need to do a function of link

All the libraries we ship with RN are in the Libraries folder in the repository. Some of them are pure Javascript code, you just need to import them to use. In addition, some libraries are implemented based on some native code. You must add these files to your application, otherwise the application will generate errors when you use these libraries.

And link is an alternative to manually linking dependencies in a project.

Manual linking is a very troublesome thing, and the solutions for Android and iOS are still different. For details, please refer to

status quo

Fortunately, but if the RN library we use is above 0.60 , we don't need to use the link instruction

In Android, it will automatically link, and in iOS, you can use cocoapods to download the native package

cocoapods

Briefly, CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects.
By analogy, it can be seen as npm .

When using cocoapods, you will need the file Podfile , which can be compared to package.json
pod install ( npm install ) 下载, 下载完毕Pods文件下, lock文件:
Podfile.lock , Manifest.lock two copies

Just a word, if there is no circumvention tool pod download will become very troublesome and often get stuck

route management

There are two commonly used routing management in RN: one is React Navigation , the other is react-native-navigation

The difference between the two is that the former is through JS code, through the combination of monorepo , and through the optimization of react-native-screens and react-native-reanimated v2 and other libraries, and finally form the final native native experience

As for why most of them are placed on the js side, and what are their benefits, I will explain them in the hot update section below

The latter uses a native container as a routing interface, such as <ScreenContainer> or <Screen> , which brings native performance, features and experience, but when we use this library or integrate another library will cause some trouble

How is it different from the front end?

The routing in the APP will have a concept stack (stack) , which is the biggest difference from the web

Here is a picture to introduce:

When we go to a new page, the previous page will not be destroyed (in most cases), he is adding a new page to the stack, so in APP, we must always be careful about memory leaks

Hot update

This is one of the most commonly used and one of the biggest advantages in RN - hot update

Hot update plan

Generally there are three options:

Notes on hot updates:

  • Apple App allows the use of hot updates Apple's developer agreement , in order not to affect the user experience, it is stipulated that silent updates must be used. Google Play cannot use silent updates, and a pop-up box must inform the user that the app has an update. China's android market must use silent updates (if the pop-up box prompts, the app will be rejected by the reason of "please upload the latest version of the binary application package").
  • react-native-code-push only updates resource files, not java and Objective C, so when npm upgrades the version of the dependent package, if the localized implementation used by the dependent package, you must change the application version number at this time, and then recompile the app Publish to the app store.

Generally speaking, the process of mobile phone hot update:

Among them, detection, download, restart, etc. are all APIs provided by the npm package react-native-code-push

There is still room for further optimization of hot updates, such as: if the bundle packaged at one time is too large, and it is subpackaged, this article will not analyze it in depth.

APP update

As we mentioned above, after the native component is updated, you need to download the APP again, so how to update it conveniently?

Here is an article I wrote before, the principle is as follows:

Click here for the original text

The above hot update and APP update also have corresponding implementations on electron . For students on the web side, this is a worthwhile reference.

other differences

There are many details in the APP that are different from the Web, here are a few points

debug solution

People who have developed H5 should be familiar with vconsole . There is also a component in RN vconsole for debugging, printing console, viewing requests, displaying various information, etc.

I also packaged an RN vconsole plugin before: react-native-vconsole , which combines the advantages of multiple plugins

Action on physical keys

A unique feature on Android machines, he is a physical key

The user can directly click the physical key to go back. When returning to the most home page, a prompt needs to be displayed 再按一次退出

This requires a special adaptation to it:

 BackHandler.addEventListener('hardwareBackPress', this.handleBackPress)

  handleBackPress = () => {
    if (//如果是第一个页面) {
      const timestamp = new Date().valueOf()
      if (timestamp - firstClick > 2000) {
        firstClick = timestamp
        ToastAndroid.show('再按一次退出', ToastAndroid.SHORT)
        return true // 返回 true,意思是阻止默认操作
      }
    }
    return false
  }

Immersive status bar

There will be a scene like the status bar on the mobile phone, which is a very visual function

As you can see in the above figure, in the display of the signal and the battery, this part is the status bar in RN. We use this API to control:

 <StatusBar barStyle="dark-content" backgroundColor="#ecf0f1" />

Of course, in order to adapt to various situations (in the APP, the status bar needs to be modified when the page enters, leaves, and other small functions change), sometimes some pages need a transparent status bar, and some special settings are also required.

Many times this component is not used directly, and needs to be packaged to adapt to most pages

version change

There are several versions in RN that are big breaking changes

  • 0.59-0.60 upgrade

There are a lot of breaking changes directly in these two versions

The biggest change on the iOS side is that the package has become CocoaPods (already mentioned above)
This makes our package dependencies also need corresponding upgrades (more than 50% of package upgrades are expected), so the scope of impact is basically the entire project

On the Android side, the way of link has changed, and the other is the modification of the configuration of build.gradle , settings.gradle , AndroidX

Here is an introduction to the official upgrade tool: https://react-native-community.github.io/upgrade-helper/
He can compare the corresponding versions and display the changes in them

  • 0.68 upgrade

The other is the upgrade from 0.67 to 0.68. In this version change, RN has made four adjustments:

  1. JavaScript Interface (JSI) - Updates for Communication
  2. Fabric - new rendering system
  3. Turbo Modules - Enhancements to Native modules
  4. CodeGen - Static Type Checker

Because this is a very low-level modification, it may cause changes to all existing components, and the scope of impact almost covers the global

new architecture

Here we will talk about what exactly is the update in 0.68

JavaScript Interface (JSI)

The original architecture I have mentioned above, some problems with him:
At present, RN uses Bridge Module communication (which also requires data conversion and decoding), and the messages sent are asynchronous in nature, that is to say, if it is an operation with high immediacy, such as dragging and dropping, there will be errors. frame situation

In the new architecture, Bridge will be replaced by a module called JavaScript Interface, which is a lightweight general-purpose layer written in C++, which can be used by JavaScript Engine to execute directly or call native.

principle

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 directly call the corresponding methods.

A simple example is

This is similar to how JS code in the web can hold a reference to any DOM element and call methods on it:

const container = document.createElement(‘div’);

If you have experience with electron , the original communication mode is the same as the communication between the main process and the rendering process in electron

Fabric

In the old architecture, the RN layout was asynchronous, which resulted in layout "jitter" when rendering nested RN views in the host view.

The new architecture, like JSI, adopts a cross-platform solution and shares the core C++ implementation.

The simple explanation is the UI version of JSI.

Of course there are some other advantages:

  • With the ability to multi-prioritize and synchronize events, renderers can prioritize user interactions to ensure their actions are processed in a timely manner.
  • The React Suspense integration allows you to write request data code in React more intuitively.
  • Allows you to use React Concurrent interruptible rendering in RN.
  • Easier to implement server-side rendering for RN.

Turbo Modules

In the previous architecture all Native Modules used by JS (such as bluetooth, geolocation, file storage, etc.) had to be initialized before the app was opened, which meant that even if the user didn't need a certain module, it still had to be at startup to initialize.

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

CodeGen

Codegen is mainly a static type checker used to ensure that JS code and C++ JSI can communicate normally . By using typed JS as a reference source, CodeGen will define interfaces that can be used by Turbo modules and Fabric. In addition, Codegen will be used during construction. Generate Native code to reduce runtime overhead.

skia

Now RN has also learned the Flutter skia rendering of ---95d165c38d33b3809903bb81804b109f---, but it is still in the stage of alpha release

这是一个值得期待的方向, 目前该库支持ImageTextShaderEffectsShapes , Animations and other operations

shortcoming

At present, the disadvantages of RN:

  1. The problem of the old library The current RN ecological environment is really good, but there are also many old warehouses, which are not only compatible with the RN version, but also need customization and lack of maintenance for various business needs, and cannot be repaired in time if there are issues
  2. performance
    The performance of RN is indeed much better than webview, but it is also worse than native. In very complex scenarios, native pages/components need to be used
  3. controls
    RN currently uses the antd version of the component library the most. It can support many scenarios, but it also lacks personnel maintenance.
  4. Compatible with a lot of RN upgrade issues mentioned above, in fact, RN has not yet reached the official version 1.0.0 , so many of his APIs will have break changes

Summarize

There are other problems in the article that are not explained in detail in the article, such as Android packaging and signatures, iOS listing, commonly used code and image optimization methods, font solutions,
The startup screen, the problem of the long list, etc., but these are also the details, and the comparison of the main body is basically mentioned.

In general, the current situation of RN is still very good, and the competition with flutter is not worthwhile in the future, as a front-end to expand the direction of the mobile terminal RN is the best choice

quote


Grewer
984 声望28 粉丝

Developer