热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

RN通信机制和渲染流程

前言ReactNative与传统的HybirdApp最大区别就是抛开WebView,使用JSC原生组件的方式进行渲染,那么整个App启动渲染流程又是怎

前言

React Native与传统的HybirdApp最大区别就是抛开WebView,使用JSC+原生组件的方式进行渲染,那么整个App启动/渲染流程又是怎样的呢?


一、整体框架

RN 这套框架让 JS开发者可以大部分使用JS代码就可以构建一个跨平台APP;
image

React 与 React native 的原理是相同的,都是由 Javascript 实现的虚拟DOM 来驱动界面 View 的渲染,只不过 React.js 驱动 HTML DOM 的渲染, RN 是驱动 ios/android 原生组件的渲染


二、前端页面开发及渲染


1、js入口

import { AppRegistry } from "react-native";
import App from "./src/index";AppRegistry.registerComponent("Wubacst", () => App);

把当前APP的对象注册到AppRegistry组件中, AppRegistry组件是js module


2、RN AppRegistry


  • AppRegistry 是运行所有 React Native 应用程序的 JS 入口点
  • 应用程序跟组件需要通过 AppRegistry.registerComponent 来注册它们自身
  • 然后本地系统就可以加载应用程序的包,再然后当 AppRegistry.runApplication准备就绪后就可以真正的运行该应用程序了
  • AppRegistry 在 require 序列里是 required,确保在其他模块被需求之前 JS 执行环境已经被 required

AppRegistry常用方法

//static静态方法,用来注册配置信息
static **registerConfig**(config: Array) //static静态方法,注册组件
static **registerComponent**(appKey: string, getComponentFunc: Function) //static静态方法,注册线程
static **registerRunnable**(appKey: string, func: Function) //static静态方法,进行运行应用
static **runApplication**(appKey: string, appParameters: any)

runApplication: function runApplication(appKey, appParameters) {var msg = 'Running application "' + appKey + '" with appParams: ' + JSON.stringify(appParameters) + '. ' + '__DEV__ === ' + String(__DEV__) + ', development-level warning are ' + (__DEV__ ? 'ON' : 'OFF') + ', performance optimizations are ' + (__DEV__ ? 'OFF' : 'ON');infoLog(msg);BugReporting.addSource('AppRegistry.runApplication' + runCount++, function () {return msg;});invariant(runnables[appKey] && runnables[appKey].run, 'Application ' + appKey + ' has not been registered.\n\n' + "Hint: This error often happens when you're running the packager " + '(local dev server) from a wrong folder. For example you have ' + 'multiple apps and the packager is still running for the app you ' + 'were working on before.\nIf this is the case, simply kill the old ' + 'packager instance (e.g. close the packager terminal window) ' + 'and start the packager in the correct app folder (e.g. cd into app ' + "folder and run 'npm start').\n\n" + 'This error can also happen due to a require() error during ' + 'initialization or failure to call AppRegistry.registerComponent.\n\n');SceneTracker.setActiveScene({name: appKey});runnables[appKey].run(appParameters);}

3、ReactDOM.render

ReactDOM.render是React的最基本方法用于将模板转为HTML语言,并插入指定的DOM节点。


ReactDOM.render(template,targetDOM),该方法接收两个参数:



  • 第一个是创建的模板
  • 第二个参数是插入该模板的目标位置

ReactDOM.render(,document.getElementById('app')
);

4、RN组件的生命周期

像 Android和iOS 开发一样,React Native(RN) 中的组件也有生命周期(Lifecycle);
当应用启动,React Native在内存中维护着一个虚拟DOM,组件的生命周期就是指组件初始化并挂载到虚拟DOM为起始,到组件从虚拟DOM卸载为终结。生命周期的方法就是组件在虚拟DOM中不同状态的描述。
image
组件的生命周期分为三个阶段:


  • 挂载(mounting
  • 更新(updating)
  • 卸载(Unmounting

组件挂载

挂载指的是组件的实例被创建并插入到DOM中,挂载会调用如下方法。
挂载阶段调用方法:

constructor(props) {super(props);this.state = {text: '构造方法'};
}

constructor是RN组件的构造方法,它在RN组件被加载前先被调用。当我们的组件继承自React.Component时,需要在构造方法中最先调用super(props)。如果不需要初始化state,则不需要实现构造方法。

componentWillMount()

componentWillMount方法在挂载前被立即调用。它在render方法前被执行,因此,在componentWillMount方法中设置state并不会导致重新被渲染。它只会被执行一次

render()

渲染,render方法中不应该修改组件的props和state;render方法在更新阶段也会被调用,前提是shouldComponentUpdate方法返回true。

componentDidMount()

componentDidMount方法在组件被挂载后立即调用,在render方法后被执行

可以在这个方法中获取其中的元素或者子组件,需要注意的是,子组件的componentDidMount方法会在父组件的componentDidMount方法之前调用

如果需要从网络加载数据显示到界面上,最好在这里进行网络请求。在componentDidMount方法中设置state将会被重新渲染。


组件更新

改变props或者state时可以导致更新,当一个组件被重新渲染时,会调用如下方法。

componentWillReceiveProps(nextProps)

componentWillReceiveProps方法会在挂载的组件接收到新的props时被调用,它接收一个Object类型参数nextProps,表示新的props。通常在这个方法中接收新的props值,并根据props的变化,通过调用 this.setState() 来更新组件state,this.setState()不会触发 render方法的调用。

在挂载的过程中,初始的props并不会触发调用componentWillReceiveProps方法,这个方法只会在组件中的props更新时被调用,另外,调用this.setState()也不会触发调用componentWillReceiveProps方法。

shouldComponentUpdate(nextProps, nextState)

当组件接收到新的props和state时,shouldComponentUpdate方法被调用,它接收两个Object参数,nextProps是新的props,nextState是新的state。

shouldComponentUpdate方法默认返回true,用来保证数据变化时,组件能够重新渲染。你也可以重载这个方法,通过检查变化前后props和state,来决定组件是否需要重新渲染。如果返回false,则组件不会被重新渲染,也不会调用本方法后面的componentWillUpdate和componentDidUpdate方法。

componentWillUpdate(nextProps, nextState)

如果组件props或者state改变,并且此前的shouldComponentUpdate方法返回为 true,则会调用该方法。componentWillUpdate方法会在组件重新渲染前被调用,因此,可以在这个方法中为重新渲染做一些准备工作。需要注意的是,在这个方法中,不能使用 this.setState 来更改state,如果想要根据props来更改state,需要在componentWillReceiveProps方法中去实现,而不是在这里

componentDidUpdate(prevProps, prevState)

组件重新渲染完成后会调用componentDidUpdate方法。两个参数分别是渲染前的props和渲染前的state。这个方法也适合写网络请求,比如可以将当前的props和prevProps进行对比,发生变化则请求网络。


组件卸载

卸载就是从DOM中删除组件,会调用如下方法

componentWillUnmount()

componentWillUnmount方法在组件卸载和销毁之前被立即调用。可以在这个方法中执行必要的清理工作,比如,关掉计时器、取消网络请求、清除组件装载中创建的DOM元素等等。


三、React Native如何把React转化为元素的API


React Native会在一开始生成OC模块表,然后把这个模块表传入JS中,JS参照模块表,就能间接调用OC的代码。


相当于买了一个机器人(OC),对应一份说明书(模块表),用户(JS)参照说明书去执行机器人的操作


四、React Native如何如何做到JS和OC交互


iOS原生API有个JavascriptCore框架,通过它就能实现JS和OC交互



  1. 首先写好前端jsx代码
  2. 把jsx代码解析成Javascript代码
  3. OC读取JS文件
  4. 把Javascript读取出来,利用JavascriptCore执行
  5. Javascript代码返回一个数组,数组中会描述OC对象,OC对象的属性,OC对象所需要执行的方法,这样就能让这个对象设置属性,并且调用方法

image


五、RN启动流程(iOS)

流程图:
image


1、创建RCTRootView


设置窗口根控制器的View,把RN的View添加到窗口上显示


我们使用RCTRootView将React Natvie视图封装到原生组件中。RCTRootView是一个UIView容器,承载着React Native应用。同时它也提供了一个联通原生端和被托管端的接口

RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridgemoduleName:@"Wubacst"initialProperties:props];

import { AppRegistry } from "react-native";
import App from "./src/index";AppRegistry.registerComponent("Wubacst", () => App);

2、创建RCTBridge


桥接对象,管理JS和OC交互,做中转左右


1、RCTBridgeModule
在React Native中,如果实现一个原生模块,需要实现RCTBridgeModule”协议

2、RCT_EXPORT_MODULE()
如果我们实现了RCTBridgeModule协议,我们的类需要包含RCT_EXPORT_MODULE()宏。这个宏也可以添加一个参数用来指定在Javascript中访问这个模块的名字。如果你不指定,默认就会使用这个Objective-C类的名字

3、RCT_EXPORT_METHOD()
与此同时我们需要声明RCT_EXPORT_METHOD()宏来实现要给Javascript导出的方法,否则React Native不会导出任何方法。

native方法注册示例:

@implementation LoadPageManager
RCT_EXPORT_MODULE()// RN跳转Native //
RCT_EXPORT_METHOD(showCSTNativePage:(NSDictionary*)commonParamesdisappearCallBack:(RCTResponseSenderBlock) disappearCallBack)
{NSLog(@"start load");NSString* pagePath = [commonParames objectForKey:@"pagePath"];NSDictionary* aParams = [commonParames objectForKey:@"params"];NSString* aPostMessageEvent = [commonParames objectForKey:@"postMessageEvent"];NSInteger isCloseParent = [(NSNumber*)[commonParames objectForKey:@"isDestoryBeforePage"] intValue];NSString* aAppearEvent = [commonParames objectForKey:@"appearEvent"];NSMutableDictionary* aTmpDic = [NSMutableDictionary dictionaryWithDictionary:commonParames];// 以下代码不要删除 //NSMutableDictionary* aDic;if (aParams){aDic = [NSMutableDictionary dictionaryWithDictionary:aParams];}if (aPostMessageEvent){[aDic setValue:aPostMessageEvent forKey:PostEvent];}if (aAppearEvent){[aDic setValue:aAppearEvent forKey:AppearEvent];}// 以下代码不要删除 //if (disappearCallBack){[aTmpDic setValue:disappearCallBack forKey:DisappearCallBack];}if (isCloseParent){[self RNBackAction];}// 转一下子为了和之前Hybrid 一致 //pagePath = [pagePath stringByReplacingOccurrencesOfString:@"_" withString:@"/"];aDic = [self adpatToHybridParmers:[NSMutableDictionary dictionaryWithDictionary:aTmpDic]]; // 后期重做考虑去掉 //// 转一下子为了和之前Hybrid 一致 //dispatch_async(dispatch_get_main_queue(), ^{[[CHRDispatcher sharedDispatcher] invokeForPath:pagePath andParams: aDic];});
}

js调用示例:

import { NativeModules, Platform } from "react-native";
import checker from "../lib/checker";
let pageManager = NativeModules.LoadPageManager;
function nativeBridge(type, params, disappearCallBack) {pageManager[type](params, disappearCallBack);
}
//RN跳转native页面
function jumpNativePage({ pagePath, isDestoryBeforePage = 0, jumpParameter, appearEvent, postMessageEvent, ...other },disappearCallBack = (error, nativeData) => {} //回调函数
) {const error = checker(arguments,[{pagePath: "s|r",isDestoryBeforePage: "b",jumpParameter: "o",appearEvent: "s",postMessageEvent: "s",...other},"f"],"jumpNativePage");// 线上环境报错不调起 Native 的 APIif (error === "error") {return error;}let param = {pagePath,jumpParameter,appearEvent,postMessageEvent, //事件名称isDestoryBeforePage, //0:不关闭,1关闭...other};nativeBridge("showCSTNativePage", param, disappearCallBack);
}

3、创建RCTBatchedBridge


批量桥接对象,JS和OC交互具体实现都在这个类中


4、执行[RCTBatchedBridge loadSource]


加载JS源码


5、执行[RCTBatchedBridge initModulesWithDispatchGroup


创建OC模块表


6、执行[RCTJSCExecutor injectJSONText]


往JS中插入OC模块表


7、执行完JS代码,回调OC,调用OC中的组件

8、完成UI渲染


六、RN UI控件渲染流程

1、RCTRootView runApplication:bridge


通知JS运行App


2、RCTBatchedBridge _processResponse:json error:error


处理执行完JS代码(runApplication)返回的相应,包含需要添加多少子控件的信息。


3、RCTBatchedBridge batchDidComplete


RCTUIManager调用处理完成的方法,就会开始去加载rootView的子控件。


4、RCTUIManager createView:viewName:rootTag:props


通过JS执行OC代码,让UI管理者创建子控件View


通过RCT_EXPORT_METHOD宏定义createView这个方法

RCT_EXPORT_METHOD(createView:(nonnull NSNumber *)reactTagviewName:(NSString *)viewNamerootTag:(nonnull NSNumber *)rootTagprops:(NSDictionary *)props)

RCT_EXPORT_METHOD宏:会在JS中生成对应的OC方法,这样JS就能直接调用

注意每创建一个UIView,就会创建一个RCTShadowView,与UIView一一对应

RCTShadowView:保存对应UIView的布局和子控件,管理UIView的加载

5、[RCTUIManager _layoutAndMount]


布局RCTRootView和增加子控件


6、[RCTUIManager setChildren:reactTags:]


给RCTRootView对应的RCTRootShadowView设置子控件


注意:此方法也是JS调用OC方法

7、[RCTRootShadowView insertReactSubview:view atIndex:index++]


遍历子控件数组,给RCTRootShadowView插入所有子控件


8、[RCTShadowView processUpdatedProperties:parentProperties:]


处理保存在RCTShadowView中属性,就会去布局RCTShadowView对应UIView的所有子控件


9、[RCTView didUpdateReactSubviews]


给原生View添加子控件


10、完成UI渲染

image


七、RN通信机制

OC生成一张模块配置表,包含所有模块和模块里的方法,根据特定的标识宏(RCT_EXPORT_MODULE()),将可以暴露的方法暴露给JS。

OC-JS交互流程:



  1. js调用OC模块暴露出来的方法
  2. 把调用方法分解为ModuleName、MethodName、arguments,在丢给MessageQueue处理
  3. 把js的callback函数缓存在MessageQueue的一个成员变量里面,同时生成一个CallbackID来代表callback;在通过保存在MessageQueue的模块配置表把ModuleName、MethodName转成ModuleID、MethodID
  4. 把ModuleID、MethodID、CallbackID和其他参数传给OC(JavascriptCore)
  5. OC接到消息,通过模块配置表拿到对于的模块和方法
  6. RCTModuleMethod对js传过来的参数进行处理
  7. OC模块方法执行完,执行block回调
  8. 调用第6步中RCTModuleMethod生成的block
  9. block带着CallbackID和block传过来的参数去掉用js里的MessageQueue方法invokeCallbackAndReturnFlushedQueue
  10. MessageQueue通过CallbackID找到相应的js的callback方法
  11. 调用callback方法,并把OC带过来的参数一起传过去完成回调

React Native用iOS自带的JavascriptCore作为JS的解析引擎,但并没有用到JavascriptCore提供的一些可以让JS与OC互调的特性,而是自己实现了一套机制,这套机制可以通用于所有JS引擎上,在没有JavascriptCore的情况下也可以用webview代替,实际上项目里就已经有了用webview作为解析引擎的实现,应该是用于兼容iOS7以下没有JavascriptCore的版本

通信过程


所谓的通信其实就是js和oc两者如何相互调用传参等



  • 程序一开始native会调用js的RCTDeviceEventEmitter.emit方法
  • 分别发送’appStateDidChange’ 和’networkStatusDidChange’两个事件

iOS端:
if (![connectionType isEqualToString:self->_connectionType] ||![effectiveConnectionType isEqualToString:self->_effectiveConnectionType] ||![status isEqualToString:self->_statusDeprecated]) {self->_connectionType = connectionType;self->_effectiveConnectionType = effectiveConnectionType;self->_statusDeprecated = status;[self sendEventWithName:@"networkStatusDidChange" body:@{@"connectionType": connectionType,@"effectiveConnectionType": effectiveConnectionType,@"network_info": status}];}if (![newState isEqualToString:_lastKnownState]) {_lastKnownState = newState;[self sendEventWithName:@"appStateDidChange"body:@{@"app_state": _lastKnownState}];}//以上这些方法都是RN提供给iOS的在RCTAppState.m中

RN端:
if (type === 'change') {this._eventHandlers[type].set(handler, this.addListener('appStateDidChange', function (appStateData) {handler(appStateData.app_state);}));} else if (type === 'memoryWarning') {this._eventHandlers[type].set(handler, this.addListener('memoryWarning', handler));}

  • 接着调用js的AppRegistry.runApplication方法启动js应用
  • 然后js层就可以通过native提供的方法来 RCTUIManager.createView来创建视图了

2、RN端发消息到iOS的过程


  • 首先在iOS里面新建一个类LoadPageManager
  • LoadPageManager会实现RCTBridgeModule协议
  • 在LoadPageManager累的实现中添加宏定义:RCT_EXPORT_MODULE()
  • RCT_EXPORT_MODULE()如果你不传入参数,那么你在iOS中导出的模块名就是类名,你也可以插入参数作为自定义模块名

iOS端代码
@implementation LoadPageManager
//可以指定一个参数来访问这个模块,不指定就是这个类的名字(ExampleInterface)
RCT_EXPORT_MODULE()
@end

接下来就可以实现协议的代理方法了,协议方法的实现需要在RCT_EXPORT_METHOD这个宏里面;下面以一个页面跳转的方法示例:

@implementation LoadPageManager
RCT_EXPORT_MODULE()// RN跳转Native //
// showCSTNativePage和前端交互的具体方法宏定义 //
// 在方法宏定义里面约定和前端交互的参数传递格式 //
RCT_EXPORT_METHOD(showCSTNativePage:(NSDictionary*)commonParamesdisappearCallBack:(RCTResponseSenderBlock) disappearCallBack)
{NSLog(@"start load");//接收解析前端传参NSString* pagePath = [commonParames objectForKey:@"pagePath"];NSDictionary* aParams = [commonParames objectForKey:@"params"];NSString* aPostMessageEvent = [commonParames objectForKey:@"postMessageEvent"];NSInteger isCloseParent = [(NSNumber*)[commonParames objectForKey:@"isDestoryBeforePage"] intValue];NSString* aAppearEvent = [commonParames objectForKey:@"appearEvent"];NSMutableDictionary* aTmpDic = [NSMutableDictionary dictionaryWithDictionary:commonParames];// 以下代码不要删除 //NSMutableDictionary* aDic;if (aParams){aDic = [NSMutableDictionary dictionaryWithDictionary:aParams];}if (aPostMessageEvent){[aDic setValue:aPostMessageEvent forKey:PostEvent];}if (aAppearEvent){[aDic setValue:aAppearEvent forKey:AppearEvent];}// 以下代码不要删除 ////回调函数,页面返回时执行if (disappearCallBack){[aTmpDic setValue:disappearCallBack forKey:DisappearCallBack];}if (isCloseParent){[self RNBackAction];}// 转一下子为了和之前Hybrid 一致 //pagePath = [pagePath stringByReplacingOccurrencesOfString:@"_" withString:@"/"];aDic = [self adpatToHybridParmers:[NSMutableDictionary dictionaryWithDictionary:aTmpDic]]; // 后期重做考虑去掉 //// 转一下子为了和之前Hybrid 一致 //dispatch_async(dispatch_get_main_queue(), ^{[[CHRDispatcher sharedDispatcher] invokeForPath:pagePath andParams: aDic];});
}

RCTBatchedBridge


为了桥接js跟native,native层引入了RCTBridge这个类负责双方的通信,不过真正起作用的是RCTBatchedBridge这个类,这个类应该算是比较重要的一个类了


通信在前端的实现:


RN层Libraries/BatchedBridge包下面有3个JS文件:BatchedBridge.js、MessageQueue.js、NativeModules.js,它们封装了通信桥在RN层的实现。


image


BatchedBridge.js

'use strict';const MessageQueue = require('MessageQueue');// MessageQueue can install a global handler to catch all exceptions where JS users can register their own behavior
// This handler makes all exceptions to be handled inside MessageQueue rather than by the VM at its origin
// This makes stacktraces to be placed at MessageQueue rather than at where they were launched
// The parameter __fbUninstallRNGlobalErrorHandler is passed to MessageQueue to prevent the handler from being installed
//
// __fbUninstallRNGlobalErrorHandler is conditionally set by the Inspector while the VM is paused for initialization
// If the Inspector isn't present it defaults to undefined and the global error handler is installed
// The Inspector can still call MessageQueue#uninstallGlobalErrorHandler to uninstalled on attachconst BatchedBridge = new MessageQueue(// $FlowFixMetypeof __fbUninstallRNGlobalErrorHandler !== 'undefined' &&__fbUninstallRNGlobalErrorHandler === true, // eslint-disable-line no-undef
);// Wire up the batched bridge on the global object so that we can call into it.
// Ideally, this would be the inverse relationship. I.e. the native environment
// provides this global directly with its script embedded. Then this module
// would export it. A possible fix would be to trim the dependencies in
// MessageQueue to its minimal features and embed that in the native runtime.Object.defineProperty(global, '__fbBatchedBridge', {configurable: true,value: BatchedBridge,
});module.exports = BatchedBridge;

可以看到在BatchedBridge中创建了MessageQueue对象


MessageQueue.js

MessageQueue的构造方法

class MessageQueue {//Js模块注册添加到_lazyCallableModules_lazyCallableModules: {[key: string]: (void) => Object};//队列,分别存放要调用的模块数组、方法数组、参数数组与数组大小_queue: [number[], number[], any[], number];//回调函数数组,与_quueue一一对应,每个_queue中调用的方法,如果有回调方法,那么就在这个数组对应的下标上。_successCallbacks: (?Function)[];_failureCallbacks: (?Function)[];//调用函数ID,自动增加。_callID: number;_inCall: number;_lastFlush: number;_eventLoopStartTime: number;_debugInfo: {[number]: [number, number//Module Table,用于Native Module_remoteModuleTable: {[number]: string};//Method Table,用于Native Module_remoteMethodTable: {[number]: string[]};__spy: ?(data: SpyData) => void;__guard: (() => void) => void;constructor(shouldUninstallGlobalErrorHandler: boolean = false) {this._lazyCallableModules = {};this._queue = [[], [], [], 0];this._successCallbacks = [];this._failureCallbacks = [];this._callID = 0;this._lastFlush = 0;this._eventLoopStartTime = new Date().getTime();if (shouldUninstallGlobalErrorHandler) {this.uninstallGlobalErrorHandler();} else {this.installGlobalErrorHandler();}if (__DEV__) {this._debugInfo = {};this._remoteModuleTable = {};this._remoteMethodTable = {};}//绑定函数,也就是创建一个函数,使这个函数不论怎么调用都有同样的this值(this: any).callFunctionReturnFlushedQueue = this.callFunctionReturnFlushedQueue.bind(this,);(this: any).callFunctionReturnResultAndFlushedQueue = this.callFunctionReturnResultAndFlushedQueue.bind(this,);(this: any).flushedQueue = this.flushedQueue.bind(this);(this: any).invokeCallbackAndReturnFlushedQueue = this.invokeCallbackAndReturnFlushedQueue.bind(this,);}
}

NativeModules.js

NativeModules描述了Module的结构,用于解析并生成Module。


Module的结构定义如下所示

type ModuleConfig = [string, /* name */?Object, /* constants */Array, /* functions */Array, /* promise method IDs */Array, /* sync method IDs */
];

RN通过NativeModules来实现传输和接受消息
首先前端页面要引入NativeModules模块


import { NativeModules, Platform } from "react-native";

然后在我们需要使用的时候获取导出的模块,我们再用模块调用iOS的导出的函数名就可以了

let pageManager = NativeModules.LoadPageManager;
function nativeBridge(type, params, disappearCallBack) {pageManager[type](params, disappearCallBack);
}
//RN跳转native页面
function jumpNativePage({ pagePath, isDestoryBeforePage = 0, jumpParameter, appearEvent, postMessageEvent, ...other },disappearCallBack = (error, nativeData) => {} //回调函数
) {const error = checker(arguments,[{pagePath: "s|r",isDestoryBeforePage: "b",jumpParameter: "o",appearEvent: "s",postMessageEvent: "s",...other},"f"],"jumpNativePage");// 线上环境报错不调起 Native 的 APIif (error === "error") {return error;}let param = {pagePath,jumpParameter,appearEvent,postMessageEvent, //事件名称isDestoryBeforePage, //0:不关闭,1关闭...other};nativeBridge("showCSTNativePage", param, disappearCallBack);
}
//showCSTNativePage约定此方法接收两个参数,一个是页面跳转需要的所有必填参数,是一个json对象,一个是页面返回时的回调函数,是Function类型

整个调用过程
image


3、native给RN主动发送事件

官网解释:
最好的方法是继承RCTEventEmitter,实现suppportEvents方法并调用self sendEventWithName:。

Javascript代码可以创建一个包含你的模块的NativeEventEmitter实例来订阅这些事件

iOS端导出方法

@implementation NativeNotification
RCT_EXPORT_MODULE();- (NSArray*) supportedEvents
{return @[AppearEvent];
}

RN端调用

import { NativeEventEmitter, NativeModules } from "react-native";
//NativeNotification是native监听事件的方法定义宏
//addListener是native监听事件的模块定义宏
const { NativeNotification } = NativeModules;
const eventManagerEmitter = new NativeEventEmitter(NativeNotification);//在组件中使用componentWillMount() {this.listener = eventManagerEmitter.addListener('viewAppear', (nativeData)=>{//nativeData native端返回数据console.log(JSON.stringify(nativeData))}); //对应了原生端的名字}//记得removecomponentWillUnmount() {this.listener && this.listener.remove();

总结:
其实就是iOS端设置了桥接内容,将收到的通知内容传递给RN,然后RN监听有没有对应Name的事件名,有的话就处理


推荐阅读
  • Vue基础一、什么是Vue1.1概念Vue(读音vjuː,类似于view)是一套用于构建用户界面的渐进式JavaScript框架,与其它大型框架不 ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
  • React基础篇一 - JSX语法扩展与使用
    本文介绍了React基础篇一中的JSX语法扩展与使用。JSX是一种JavaScript的语法扩展,用于描述React中的用户界面。文章详细介绍了在JSX中使用表达式的方法,并给出了一个示例代码。最后,提到了JSX在编译后会被转化为普通的JavaScript对象。 ... [详细]
  • 认识Vue关于Vue的描述有不少,不外乎都会拿来与Angular和React对比,同样头顶MVVM双向数据驱动设计模式光环的Angular自然被对比的最多,但到目前为止,Angul ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • Java和JavaScript是什么关系?java跟javaScript都是编程语言,只是java跟javaScript没有什么太大关系,一个是脚本语言(前端语言),一个是面向对象 ... [详细]
  • 从零基础到精通的前台学习路线
    随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
  • 本文介绍了自学Vue的第01天的内容,包括学习目标、学习资料的收集和学习方法的选择。作者解释了为什么要学习Vue以及选择Vue的原因,包括完善的中文文档、较低的学习曲线、使用人数众多等。作者还列举了自己选择的学习资料,包括全新vue2.5核心技术全方位讲解+实战精讲教程、全新vue2.5项目实战全家桶单页面仿京东电商等。最后,作者提出了学习方法,包括简单的入门课程和实战课程。 ... [详细]
  • React 小白初入门
    推荐学习:React官方文档:https:react.docschina.orgReact菜鸟教程:https:www.runoob.c ... [详细]
  • 腾讯T3大牛亲自教你!2021大厂Android面试经验,经典好文
    本篇将由环境搭建、实现原理、编程开发、插件开发、编译运行、性能稳定、发展未来等七个方面,对当前的ReactNative和Flutter进行全面的分析对比, ... [详细]
  • 前言作为一个移动端初学者、爱好者,能使用前端技术开发原生游戏一直是一件渴望而不可及的事情,暂且不说游戏逻辑的复杂度,算法的健壮性ÿ ... [详细]
  • 安卓端开源移动浏览器开源项目
    进入android开发以来,webview用的比较多,后来又看了一些基于webview的浏览器代码,慢慢的将积累的东西做成了一个安卓移动浏 ... [详细]
  • webui之常用js操作(webui界面是什么)
    本文目录一览:1、web前端开发需要掌握的几个必备技术 ... [详细]
author-avatar
会满足cy
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有