React-Native實(shí)踐總結(jié)

React-Native分析

RN的優(yōu)點(diǎn):

  1. 頁(yè)面熱更新
  2. RN頁(yè)面不需要移動(dòng)端發(fā)版本
  3. 純web思維,開(kāi)發(fā)速度快,且體驗(yàn)優(yōu)于h5,
  4. 第三方插件也比較多
  5. 部分功能代碼實(shí)現(xiàn)一端開(kāi)發(fā)多端共用(“Learn once,write anywhere”?)

RN的缺點(diǎn):

  1. 下載包體變大,多了一個(gè)RN的sdk
  2. 調(diào)試相對(duì)麻煩
  3. 兼容性問(wèn)題放大了
  4. 開(kāi)發(fā)要求高了,js、native都需要了解

數(shù)據(jù)的傳遞(交互):

React-Native 數(shù)據(jù)交互

RN 擁有畫(huà)UI的跨平臺(tái)能力,主要是加入Virtual DOM編程模型,該方法一方面可以照顧到JS開(kāi)發(fā)者在html DOM的部分傳承, 讓JS 開(kāi)發(fā)者可以用類(lèi)似DOM編程模型就可以開(kāi)發(fā)原生APP , 另一方面則可以讓Virtual DOM適配實(shí)現(xiàn)到各個(gè)平臺(tái),實(shí)現(xiàn)跨平臺(tái)的能力

JS與Native模塊之間通信,主要有三種方法:

  1. 使用回調(diào)函數(shù)Callback,它提供了一個(gè)函數(shù)來(lái)把返回值傳回給JavaScript。
  2. 使用Promise來(lái)實(shí)現(xiàn)。
  3. 原生模塊向JavaScript發(fā)送事件。

JS調(diào)用Native

js調(diào)用原生功能模塊需要用到RN模塊NativeModules并獲取到native的指定module

import { NativeModules } from 'react-native'
var jsToNativeEmitter = NativeModules.KJSToNativeEmitter

js調(diào)用原生組件需要用到RN模塊requireNativeComponent并獲取到native的指定組件

import { requireNativeComponent } from 'react-native'
let RTCView = requireNativeComponent('RNCustomView', RNCustomView, {})

功能模塊和組件的需要在Native中先聲明定義.如下:

JS調(diào)用Native之iOS

RCTBridgeModule橋接模塊,管理JS和OC交互, 一個(gè)“原生模塊”就是一個(gè)實(shí)現(xiàn)了“RCTBridgeModule”協(xié)議的 Objective-C 類(lèi),很重要!!

類(lèi)名:RCT_EXPORT_MODULE 標(biāo)記宏

常量:constantsToExport. 導(dǎo)出常量給js

方法:RCT_EXPORT_METHOD 導(dǎo)出方法
...等等

模塊的定義:

RCT_EXPORT_METHOD:原生方法導(dǎo)出,生成對(duì)應(yīng)js方法,供JS調(diào)用.很重要!一般通過(guò)這個(gè)宏定義的路由.但是回調(diào)不帶有屬性傳遞!!!

把callBack傳回給 JavaScript

typedef void (^RCTResponseSenderBlock)(NSArray *response);
typedef void (^RCTResponseErrorBlock)(NSError *error);

把Promise對(duì)象傳回給 JavaScript

typedef void (^RCTPromiseResolveBlock)(id result);
typedef void (^RCTPromiseRejectBlock)(NSString *code, NSString *message, NSError *error);
封裝組件的定義:

繼承RCTViewManager
實(shí)現(xiàn)view的定義
屬性:RCT_EXPORT_VIEW_PROPERTY。通過(guò)該宏完成屬性的映射和導(dǎo)出

自定義屬性:RCT_CUSTOM_VIEW_PROPERTY

事件導(dǎo)出:RCTBubblingEventBlock 通過(guò)屬性實(shí)現(xiàn)RCT_EXPORT_VIEW_PROPERTY(onXXX, RCTBubblingEventBlock)

JS調(diào)用Native之Android

類(lèi)名:需要實(shí)現(xiàn)方法public String getName()
常量: 需要實(shí)現(xiàn)public Map<String, Object> getConstants()

方法:@ReactMethod

模塊的定義:

需要在createNativeModules中聲明

public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        return Arrays.<NativeModule>asList(new KJSToNativeEmitter(reactContext));
    }
封裝組件的定義:

需要實(shí)現(xiàn)createViewInstance(ThemedReactContext reactContext)
需要在createViewManagers中聲明
需要繼承ViewManagerBaseViewManagerSimpleViewManager
屬性:@ReactProp@ReactPropGroup

@Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
//        return Collections.emptyList();
        return Arrays.<ViewManager>asList(new RNCustomViewManager());
    }

Native調(diào)用JS

native調(diào)用原生分為兩種:被動(dòng)和主動(dòng)
被動(dòng):通過(guò)js調(diào)native返回callBack或Promise的方式
主動(dòng):通過(guò)RCTDeviceEventEmitter強(qiáng)制發(fā)起事件

js調(diào)用native需要用到RN中的NativeEventEmitterNativeModules模塊,并獲取到原生指定的模塊

import { NativeEventEmitter, NativeModules } from 'react-native'
var nativeBridge = NativeModules.KNativeToJSEmitter //未定義module 就是你的類(lèi)名
const NativeModule = new NativeEventEmitter(nativeBridge)

componentDidMount(){  
  this.listener = RCTDeviceEventEmitter.addListener('通知名稱(chēng)',(value)=>{  
    // 接受到通知后的處理  
  })
}  
  
componentWillUnmount(){  
  // 移除 一定要寫(xiě)  
  this.listener.remove()
}

Native調(diào)用JS之iOS:

繼承RCTEventEmitter,并實(shí)現(xiàn)RCTBridgeModule協(xié)議
RCT_EXPORT_MODULE(xxx);指定module名

///指定module名,不傳入就是類(lèi)名
RCT_EXPORT_MODULE();
#pragma mark - 重寫(xiě)父類(lèi)方法
///返回所有原生端發(fā)往js端的消息名字
- (NSArray<NSString *> *)supportedEvents
{
    return EventEmitterNames;
}

    //發(fā)起事件
    [self sendEventWithName:emitterName body:object];

Native調(diào)用JS之Android:

需要獲取到當(dāng)前的ReactContext,并通過(guò)它來(lái)發(fā)事件

    //發(fā)消息
    private static final String KEventName = "KNativeToJSEmitter";

    public void sendEvent(ReactContext reactContext,
                           @Nullable WritableMap params) {
        if (reactContext==null) {
            Log.i(TAG, "reactContext==null");
        }else{
            reactContext
                    .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                    .emit(KEventName, params);
        }
    }

總結(jié)

對(duì)于大多數(shù)app開(kāi)發(fā)者來(lái)說(shuō),ReactNative沒(méi)有想象中的難,但也有不少坑.個(gè)人覺(jué)得RN不宜覆蓋整個(gè)app,適用于app內(nèi)某些活動(dòng)頁(yè), 使用時(shí)盡量少用原生層次自定義的組件,可以用js來(lái)封裝基礎(chǔ)組件!這樣子在版本迭代的時(shí)候會(huì)輕松點(diǎn).

js調(diào)用native統(tǒng)一入口,定個(gè)規(guī)則

RCT_EXPORT_METHOD(sendMsg:(NSInteger)msgType
                  message:(NSString *)msg) 
                 resolver:(RCTPromiseResolveBlock)resolver
                 rejecter:(RCTPromiseRejectBlock)reject){   
}

@ReactMethod
  public void sendMsg(
      int msgType,
      String msg,
      Promise promise)

msgType:事件類(lèi)型
msg:傳遞的具體消息 類(lèi)似路由

附:

React-Native官方安裝教程:https://reactnative.cn/docs/getting-started.html

@ReactMethod注明的方法中 native 與 js類(lèi)型之間關(guān)系
js與iOS:

string (NSString)
number (NSInteger, float, double, CGFloat, NSNumber)
boolean (BOOL, NSNumber)
array (NSArray) 可包含本列表中任意類(lèi)型
object (NSDictionary) 可包含 string 類(lèi)型的鍵和本列表中任意類(lèi)型的值
function (RCTResponseSenderBlock)

Android與js:

Boolean -> Bool
Integer -> Number
Double -> Number
Float -> Number
String -> String
Callback -> function
ReadableMap -> Object
ReadableArray -> Array
```![![5bc6abb6e4b0534c9c063dc2.png](https://upload-images.jianshu.io/upload_images/2906485-650c96fcb9b89fd0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
](https://upload-images.jianshu.io/upload_images/2906485-59f348c9fb8a682a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容