有时我们从native发送事件到javascript时希望能够根据javascript的处理结果回调native的相关处理逻辑,RN并没有直接提供相关机制,因此我们往往需要按照以下的方式来进行模拟:
- Native发送event到JavaScript
[bridge enqueueJSCall:@"RCTDeviceEventEmitter"
method:@"emit"
args:@[@"demo", @"Request from Native"]
completion:nil];
reactContext.getJSModule(
DeviceEventManagerModule.RCTDeviceEventEmitter.class
).emit("demo", "Request from Native");
- JavaScript监听event并做处理
import React from 'react'
import { NativeModules, DeviceEventEmitter } from 'react-native';
const { MyAppManager } = NativeModules;
class MyApp extends React.PureComponent {
componentWillMount() {
DeviceEventEmitter.addListener('demo', (params) => {
//doSomething....
MyAppManager.invokeCallback({
response: 'Response from JavaScript',
});
});
}
componentWillUnmount() {
DeviceEventEmitter.removeListener('demo');
}
}
- 注册MyAppManager
//MyAppManager.h
#import <React/RCTBridgeModule.h>
@interface MyAppManager : NSObject <RCTBridgeModule>
@end
//MyAppManager.m
#import "MyAppManager.h"
@implementation MyAppManager
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(invokeCallback:(NSDictionary *)data) {
//doSomething...
}
@end
package me.tom.myapp;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
public class MyAppManager extends ReactContextBaseJavaModule {
public MyAppManager(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "MyAppManager";
}
@ReactMethod
public void invokeCallback(ReadableMap data) {
//doSomething...
}
}
上述实例中,我们在监听事件的处理方法
中通过调用在native
中定义的MyAppManager#invokeCallback
方法来通知native
端进行后续处理的方式实现了我们一开始的需求。但这样的实现个人认为存在以下几个方面的问题:
- JavaScript端必须手动调用
MyAppManager.invokeCallback(...)
,啰嗦且容易忘记。 - Native发送事件的地方一般是在UIViewController、Activity或Fragment中,因此
MyAppManager
还需要根据不用的参数将执行任务派发到相应真实的处理方法中,这里将充斥着大量的模版代码且易于出错。
针对上面的问题,个人简单的封装了一个库,上面的实例就可以简化为:
- Native发送event到JavaScript并执行回调
#import "ZMReactEventEmitter.h"
RCTBridge *bridge = ....
ZMReactEventEmitter *eventEmitter = [ZMReactEventEmitter new];
[eventEmitter sendEvent:bridge name:@"demo" params:@"Request from Native" callback:^(id data) {
//doSomething...
}];
import me.tom.react.event.ReactEventEmitter;
import me.tom.react.event.ReactEventEmitterCallbackHandler;
ReactContext context = ...;
ReactEventEmitter eventEmitter = new ReactEventEmitter();
eventEmitter.sendEvent(context, "demo", "Request from Native", new ReactEventEmitterCallbackHandler() {
@Override
public void handler(ReadableMap data) {
//doSomething...
}
});
- JavaScript监听事件并触发回调
import React from 'react';
import ReactEventEmitter from 'rn-event-emitter-callback';
class MyApp extends React.PureComponent {
componentWillMount() {
ReactEventEmitter.addListener('demo', (params, callback) => {
//doSomething...
callback('Response from React Native');
})
}
componentWillUnmount() {
ReactEventEmitter.removeListener('demo');
}
}
通过对比,是不是觉得这种方式更符合我们的直观认知,关于该库的详细信息,请移步:https://github.com/nanjingboy/React-Native-Event ^ _ ^
网友评论